|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <stdbool.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sys/mman.h>
 | 
					
						
							|  |  |  | #include <sys/socket.h>
 | 
					
						
							|  |  |  | #include <sys/un.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ipc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ipc_connect(const char* socket_path) {
 | 
					
						
							|  |  |  |   int err;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef __APPLE__
 | 
					
						
							|  |  |  |   int sock = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |   if (sock < 0) return -1;
 | 
					
						
							|  |  |  |   struct sockaddr_un addr = {
 | 
					
						
							|  |  |  |     .sun_family = AF_UNIX,
 | 
					
						
							|  |  |  |   };
 | 
					
						
							|  |  |  |   snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
 | 
					
						
							|  |  |  |   err = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
 | 
					
						
							|  |  |  |   if (err != 0) {
 | 
					
						
							|  |  |  |     close(sock);
 | 
					
						
							|  |  |  |     return -1;
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return sock;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ipc_bind(const char* socket_path) {
 | 
					
						
							|  |  |  |   int err;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   unlink(socket_path);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef __APPLE__
 | 
					
						
							|  |  |  |   int sock = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |   struct sockaddr_un addr = {
 | 
					
						
							|  |  |  |     .sun_family = AF_UNIX,
 | 
					
						
							|  |  |  |   };
 | 
					
						
							|  |  |  |   snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
 | 
					
						
							|  |  |  |   err = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
 | 
					
						
							|  |  |  |   assert(err == 0);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   err = listen(sock, 3);
 | 
					
						
							|  |  |  |   assert(err == 0);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return sock;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds,
 | 
					
						
							|  |  |  |                           int *out_num_fds) {
 | 
					
						
							|  |  |  |   char control_buf[CMSG_SPACE(sizeof(int) * num_fds)];
 | 
					
						
							|  |  |  |   memset(control_buf, 0, CMSG_SPACE(sizeof(int) * num_fds));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   struct iovec iov = {
 | 
					
						
							|  |  |  |     .iov_base = buf,
 | 
					
						
							|  |  |  |     .iov_len = buf_size,
 | 
					
						
							|  |  |  |   };
 | 
					
						
							|  |  |  |   struct msghdr msg = {
 | 
					
						
							|  |  |  |     .msg_iov = &iov,
 | 
					
						
							|  |  |  |     .msg_iovlen = 1,
 | 
					
						
							|  |  |  |   };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (num_fds > 0) {
 | 
					
						
							|  |  |  |     assert(fds);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     msg.msg_control = control_buf;
 | 
					
						
							|  |  |  |     msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (send) {
 | 
					
						
							|  |  |  |     if (num_fds) {
 | 
					
						
							|  |  |  |       struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
 | 
					
						
							|  |  |  |       assert(cmsg);
 | 
					
						
							|  |  |  |       cmsg->cmsg_level = SOL_SOCKET;
 | 
					
						
							|  |  |  |       cmsg->cmsg_type = SCM_RIGHTS;
 | 
					
						
							|  |  |  |       cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
 | 
					
						
							|  |  |  |       memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * num_fds);
 | 
					
						
							|  |  |  |       // printf("send clen %d -> %d\n", num_fds, cmsg->cmsg_len);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     return sendmsg(fd, &msg, 0);
 | 
					
						
							|  |  |  |   } else {
 | 
					
						
							|  |  |  |     int r = recvmsg(fd, &msg, 0);
 | 
					
						
							|  |  |  |     if (r < 0) return r;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int recv_fds = 0;
 | 
					
						
							|  |  |  |     if (msg.msg_controllen > 0) {
 | 
					
						
							|  |  |  |       struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
 | 
					
						
							|  |  |  |       assert(cmsg);
 | 
					
						
							|  |  |  |       assert(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS);
 | 
					
						
							|  |  |  |       recv_fds = (cmsg->cmsg_len - CMSG_LEN(0));
 | 
					
						
							|  |  |  |       assert(recv_fds > 0 && (recv_fds % sizeof(int)) == 0);
 | 
					
						
							|  |  |  |       recv_fds /= sizeof(int);
 | 
					
						
							|  |  |  |       // printf("recv clen %d -> %d\n", cmsg->cmsg_len, recv_fds);
 | 
					
						
							|  |  |  |       // assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int) * num_fds));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       assert(fds && recv_fds <= num_fds);
 | 
					
						
							|  |  |  |       memcpy(fds, CMSG_DATA(cmsg), sizeof(int) * recv_fds);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (msg.msg_flags) {
 | 
					
						
							|  |  |  |       for (int i=0; i<recv_fds; i++) {
 | 
					
						
							|  |  |  |         close(fds[i]);
 | 
					
						
							|  |  |  |       }
 | 
					
						
							|  |  |  |       return -1;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (fds) {
 | 
					
						
							|  |  |  |       assert(out_num_fds);
 | 
					
						
							|  |  |  |       *out_num_fds = recv_fds;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     return r;
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | }
 |