Skip to content

Instantly share code, notes, and snippets.

@gnif
Last active October 31, 2019 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gnif/77e7fb54604b42a1a98ecb8bf3d2cf46 to your computer and use it in GitHub Desktop.
Save gnif/77e7fb54604b42a1a98ecb8bf3d2cf46 to your computer and use it in GitHub Desktop.
Example client for the new zero-copy shared ram device @ https://github.com/gnif/qemu/blob/master/hw/misc/porthole.c
#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 {
uint32_t id; // the ID of the FD
} __attribute__ ((packed)) PHMsgFd;
typedef struct {
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; // 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
{
PHMsgFd fd;
PHMsgSegment segment;
PHMsgFinish finish;
PHMsgUnmap unmap;
} u;
} __attribute__ ((packed)) PHMsg;
#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 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
{
uint32_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)
{
PHMsg 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 PH_MSG_MAP:
printf("Map Message\n");
break;
case PH_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%08x 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 PH_MSG_SEGMENT:
{
int i;
for(i = 0; i < 4; ++i)
if (pool[i].map && pool[i].fd_id == msg.u.segment.fd_id)
break;
if (i == 4)
{
fprintf(stderr, "No such fd_id: 0x%08x\n", msg.u.segment.fd_id);
return -1;
}
char * map = pool[i].map;
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 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;
}
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;
}
@gnif
Copy link
Author

gnif commented Oct 29, 2019

Example output:

root@moya:~/introspection# ./introspection /var/tmp/kvmfr.debug 
Reset Message
mapped fd_id 0x000000000 to 0x7fa700000000 (4294967296)
FD: 0x000000000, addr: 0x0d3f86890, size:   1904 - 00 01 00 00 00 40 00 00  54 65 73 74 20 6D 65 73  |  .....@..Test mes 
FD: 0x000000000, addr: 0x0a4bf7000, size:   4096 - 73 00 54 65 73 74 20 6D  65 73 73 61 67 65 20 66  |  s.Test message f 
FD: 0x000000000, addr: 0x0a17f8000, size:   4096 - 20 66 72 6F 6D 20 77 69  6E 64 6F 77 73 00 54 65  |   from windows.Te 
FD: 0x000000000, addr: 0x0d72f9000, size:   4096 - 54 65 73 74 20 6D 65 73  73 61 67 65 20 66 72 6F  |  Test message fro 
FD: 0x000000000, addr: 0x0991f6000, size:   2200 - 72 6F 6D 20 77 69 6E 64  6F 77 73 00 54 65 73 74  |  rom windows.Test 
Finish Message: 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment