Skip to content

Instantly share code, notes, and snippets.

@gnif
Last active October 31, 2019 11:52
Show Gist options
  • Save gnif/77e7fb54604b42a1a98ecb8bf3d2cf46 to your computer and use it in GitHub Desktop.
Save gnif/77e7fb54604b42a1a98ecb8bf3d2cf46 to your computer and use it in GitHub Desktop.

Revisions

  1. gnif revised this gist Oct 31, 2019. 1 changed file with 57 additions and 32 deletions.
    89 changes: 57 additions & 32 deletions main.c
    Original file line number Diff line number Diff line change
    @@ -8,42 +8,50 @@
    #include <sys/stat.h>

    typedef struct {
    uint64_t id;
    } __attribute__ ((packed)) MsgFd;
    uint32_t id; // the ID of the FD
    } __attribute__ ((packed)) PHMsgFd;

    typedef struct {
    uint64_t fd_id;
    uint64_t addr;
    uint32_t size;
    } __attribute__ ((packed)) MsgSegment;
    uint32_t fd_id; // the ID of the FD for this segment
    uint32_t size; // the size of this segment
    uint64_t addr; // the base address of this segment
    } __attribute__ ((packed)) PHMsgSegment;

    typedef struct {
    uint32_t type;
    } __attribute__ ((packed)) MsgFinish;
    uint32_t type; // the application defined type
    uint32_t id; // the ID of the new mapping
    } __attribute__ ((packed)) PHMsgFinish;

    typedef struct {
    uint32_t id; // the mapping ID
    } __attribute__ ((packed)) PHMsgUnmap;

    typedef struct {
    uint32_t msg;
    union
    {
    MsgFd fd;
    MsgSegment segment;
    MsgFinish finish;
    PHMsgFd fd;
    PHMsgSegment segment;
    PHMsgFinish finish;
    PHMsgUnmap unmap;
    } u;
    } __attribute__ ((packed)) Msg;
    } __attribute__ ((packed)) PHMsg;

    #define INTRO_MSG_RESET 0x1
    #define INTRO_MSG_FD 0x2
    #define INTRO_MSG_SEGMENT 0x3
    #define INTRO_MSG_FINISH 0x4
    #define PH_MSG_MAP 0x1 // start of a map sequence
    #define PH_MSG_FD 0x2 // file descriptor
    #define PH_MSG_SEGMENT 0x3 // map segment
    #define PH_MSG_FINISH 0x4 // finish of map sequence
    #define PH_MSG_UNMAP 0x5 // unmap a previous map

    #define INTRO_MSG_RESET_SIZE (sizeof(uint32_t))
    #define INTRO_MSG_FD_SIZE (sizeof(uint32_t) + sizeof(MsgFd))
    #define INTRO_MSG_SEGMENT_SIZE (sizeof(uint32_t) + sizeof(MsgSegment))
    #define INTRO_MSG_FINISH_SIZE (sizeof(uint32_t) + sizeof(MsgFinish))
    #define PH_MSG_MAP_SIZE (sizeof(uint32_t))
    #define PH_MSG_FD_SIZE (sizeof(uint32_t) + sizeof(PHMsgFd))
    #define PH_MSG_SEGMENT_SIZE (sizeof(uint32_t) + sizeof(PHMsgSegment))
    #define PH_MSG_FINISH_SIZE (sizeof(uint32_t) + sizeof(PHMsgFinish))
    #define PH_MSG_UNMAP_SIZE (sizeof(uint32_t) + sizeof(PHMsgUnmap))

    struct memorymap
    {
    uint64_t fd_id;
    uint32_t fd_id;
    int fd;
    char * map;
    size_t size;
    @@ -82,7 +90,7 @@ void DumpHex(const void* data, size_t size) {

    int process(int fd)
    {
    Msg msg;
    PHMsg msg;
    struct iovec io =
    {
    .iov_base = &msg,
    @@ -106,11 +114,11 @@ int process(int fd)

    switch(msg.msg)
    {
    case INTRO_MSG_RESET:
    printf("Reset Message\n");
    case PH_MSG_MAP:
    printf("Map Message\n");
    break;

    case INTRO_MSG_FD:
    case PH_MSG_FD:
    {
    /* get the fd */
    struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msghdr);
    @@ -146,7 +154,7 @@ int process(int fd)
    return -1;
    }

    printf("mapped fd_id 0x%09lx to %p (%lu)\n",
    printf("mapped fd_id 0x%08x to %p (%lu)\n",
    msg.u.fd.id, pool[i].map, st.st_size);
    break;
    }
    @@ -161,28 +169,45 @@ int process(int fd)
    break;
    }

    case INTRO_MSG_SEGMENT:
    case PH_MSG_SEGMENT:
    {
    int i;
    for(i = 0; i < 4; ++i)
    if (pool[i].fd_id == msg.u.segment.fd_id && pool[i].map)
    if (pool[i].map && pool[i].fd_id == msg.u.segment.fd_id)
    break;

    if (i == 4)
    {
    fprintf(stderr, "No such fd_id: 0x%09lx\n", msg.u.segment.fd_id);
    fprintf(stderr, "No such fd_id: 0x%08x\n", msg.u.segment.fd_id);
    return -1;
    }

    char * map = pool[i].map;
    printf("FD: 0x%09lx, addr: 0x%09lx, size: %6u - ", msg.u.segment.fd_id, msg.u.segment.addr, msg.u.segment.size);
    printf("FD: 0x%08x, addr: 0x%09lx, size: %6u - ", msg.u.segment.fd_id, msg.u.segment.addr, msg.u.segment.size);
    DumpHex(map + msg.u.segment.addr, msg.u.segment.size > 16 ? 16 : msg.u.segment.size);
    break;
    }

    case INTRO_MSG_FINISH:
    printf("Finish Message: %u\n", msg.u.finish.type);
    case PH_MSG_FINISH:
    printf("Type: %u, ID: %u\n", msg.u.finish.type, msg.u.finish.id);
    break;

    case PH_MSG_UNMAP:
    printf("Unmap: %u\n", msg.u.unmap.id);
    uint32_t reply = PH_MSG_UNMAP;

    msghdr.msg_controllen = 0;
    io.iov_base = &reply;
    io.iov_len = sizeof(reply);

    usleep(10000000);
    printf("Sending reply\n");
    if (sendmsg(fd, &msghdr, 0) < 0)
    {
    fprintf(stderr, "Failed to send the message\n");
    return -1;
    }
    break;
    }

    return 0;
  2. gnif created this gist Oct 29, 2019.
    233 changes: 233 additions & 0 deletions main.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,233 @@
    #include <stdio.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdint.h>
    #include <sys/mman.h>
    #include <sys/stat.h>

    typedef struct {
    uint64_t id;
    } __attribute__ ((packed)) MsgFd;

    typedef struct {
    uint64_t fd_id;
    uint64_t addr;
    uint32_t size;
    } __attribute__ ((packed)) MsgSegment;

    typedef struct {
    uint32_t type;
    } __attribute__ ((packed)) MsgFinish;

    typedef struct {
    uint32_t msg;
    union
    {
    MsgFd fd;
    MsgSegment segment;
    MsgFinish finish;
    } u;
    } __attribute__ ((packed)) Msg;

    #define INTRO_MSG_RESET 0x1
    #define INTRO_MSG_FD 0x2
    #define INTRO_MSG_SEGMENT 0x3
    #define INTRO_MSG_FINISH 0x4

    #define INTRO_MSG_RESET_SIZE (sizeof(uint32_t))
    #define INTRO_MSG_FD_SIZE (sizeof(uint32_t) + sizeof(MsgFd))
    #define INTRO_MSG_SEGMENT_SIZE (sizeof(uint32_t) + sizeof(MsgSegment))
    #define INTRO_MSG_FINISH_SIZE (sizeof(uint32_t) + sizeof(MsgFinish))

    struct memorymap
    {
    uint64_t fd_id;
    int fd;
    char * map;
    size_t size;
    };

    struct memorymap pool[4] = {0};

    void DumpHex(const void* data, size_t size) {
    char ascii[17];
    size_t i, j;
    ascii[16] = '\0';
    for (i = 0; i < size; ++i) {
    printf("%02X ", ((unsigned char*)data)[i]);
    if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
    ascii[i % 16] = ((unsigned char*)data)[i];
    } else {
    ascii[i % 16] = '.';
    }
    if ((i+1) % 8 == 0 || i+1 == size) {
    printf(" ");
    if ((i+1) % 16 == 0) {
    printf("| %s \n", ascii);
    } else if (i+1 == size) {
    ascii[(i+1) % 16] = '\0';
    if ((i+1) % 16 <= 8) {
    printf(" ");
    }
    for (j = (i+1) % 16; j < 16; ++j) {
    printf(" ");
    }
    printf("| %s \n", ascii);
    }
    }
    }
    }

    int process(int fd)
    {
    Msg msg;
    struct iovec io =
    {
    .iov_base = &msg,
    .iov_len = sizeof(msg)
    };

    char buffer[256] = {0};
    struct msghdr msghdr =
    {
    .msg_iov = &io,
    .msg_iovlen = 1,
    .msg_control = &buffer,
    .msg_controllen = sizeof(buffer)
    };

    if (recvmsg(fd, &msghdr, 0) < 0)
    {
    fprintf(stderr, "Failed to recieve the message\n");
    return -1;
    }

    switch(msg.msg)
    {
    case INTRO_MSG_RESET:
    printf("Reset Message\n");
    break;

    case INTRO_MSG_FD:
    {
    /* get the fd */
    struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msghdr);
    unsigned char * data = CMSG_DATA(cmsg);
    int memfd = *((int*)data);

    /* see if we already have this id */
    int i;
    for(i = 0; i < 4; ++i)
    if (pool[i].fd_id == msg.u.fd.id && pool[i].map)
    break;

    /* if not found */
    if (i == 4)
    {
    /* look for a free place in the pool table */
    for(i = 0; i < 4; ++i)
    {
    if (pool[i].map)
    continue;

    struct stat st;
    fstat(memfd, &st);

    pool[i].fd_id = msg.u.fd.id;
    pool[i].fd = memfd;
    pool[i].map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, memfd, 0);
    pool[i].size = st.st_size;
    if (!pool[i].map)
    {
    fprintf(stderr, "Failed to mmap the supplied fd\n");
    close(memfd);
    return -1;
    }

    printf("mapped fd_id 0x%09lx to %p (%lu)\n",
    msg.u.fd.id, pool[i].map, st.st_size);
    break;
    }

    if (i == 4)
    {
    fprintf(stderr, "mempool full\n");
    close(memfd);
    return -1;
    }
    }
    break;
    }

    case INTRO_MSG_SEGMENT:
    {
    int i;
    for(i = 0; i < 4; ++i)
    if (pool[i].fd_id == msg.u.segment.fd_id && pool[i].map)
    break;

    if (i == 4)
    {
    fprintf(stderr, "No such fd_id: 0x%09lx\n", msg.u.segment.fd_id);
    return -1;
    }

    char * map = pool[i].map;
    printf("FD: 0x%09lx, addr: 0x%09lx, size: %6u - ", msg.u.segment.fd_id, msg.u.segment.addr, msg.u.segment.size);
    DumpHex(map + msg.u.segment.addr, msg.u.segment.size > 16 ? 16 : msg.u.segment.size);
    break;
    }

    case INTRO_MSG_FINISH:
    printf("Finish Message: %u\n", msg.u.finish.type);
    break;
    }

    return 0;
    }

    int main(int argc, char *argv[])
    {
    if (argc < 2)
    {
    fprintf(stderr, "No socket specified\n");
    return -1;
    }

    int fd = socket(AF_UNIX, SOCK_STREAM, 0);

    if (fd == -1)
    {
    fprintf(stderr, "Failed to create unix socket\n");
    return -1;
    }

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path)-1);

    if (connect(fd, (const struct sockaddr*)&addr, sizeof(addr)) == -1)
    {
    fprintf(stderr, "Failed to connect to the socket\n");
    close(fd);
    return -1;
    }

    int ret = 0;
    while(ret == 0)
    ret = process(fd);

    /* cleanup */
    for(int i = 0; i < 4; ++i)
    if (pool[i].map)
    {
    munmap(pool[i].map, pool[i].size);
    close(pool[i].fd);
    }

    close(fd);
    return ret;
    }