Add functions to send/receive data & FD over a unix domain socket.
authorAndres Freund <[email protected]>
Mon, 21 May 2018 22:43:30 +0000 (15:43 -0700)
committerAndres Freund <[email protected]>
Mon, 21 May 2018 22:43:30 +0000 (15:43 -0700)
This'll be used by a followup patch changing how the fsync request
queue works, to make it safe on linux.

TODO: This probably should live elsewhere.

Author: Andres Freund
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:

src/backend/storage/file/fd.c
src/include/storage/fd.h

index 441f18dcf56e6fd679269806da46f7281c58d85d..65e46483a44bce571c01b609f76a71e610b65294 100644 (file)
@@ -3572,3 +3572,105 @@ MakePGDirectory(const char *directoryName)
 {
    return mkdir(directoryName, pg_dir_create_mode);
 }
+
+/*
+ * Send data over a unix domain socket, optionally (when fd != -1) including a
+ * file descriptor.
+ */
+ssize_t
+pg_uds_send_with_fd(int sock, void *buf, ssize_t buflen, int fd)
+{
+   ssize_t     size;
+   struct msghdr   msg = {0};
+   struct iovec    iov;
+   /* cmsg header, union for correct alignment */
+   union
+   {
+       struct cmsghdr  cmsghdr;
+       char        control[CMSG_SPACE(sizeof (int))];
+   } cmsgu;
+   struct cmsghdr  *cmsg;
+
+   iov.iov_base = buf;
+   iov.iov_len = buflen;
+
+   msg.msg_name = NULL;
+   msg.msg_namelen = 0;
+   msg.msg_iov = &iov;
+   msg.msg_iovlen = 1;
+
+   if (fd >= 0)
+   {
+       msg.msg_control = cmsgu.control;
+       msg.msg_controllen = sizeof(cmsgu.control);
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       cmsg->cmsg_len = CMSG_LEN(sizeof (int));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+
+       *((int *) CMSG_DATA(cmsg)) = fd;
+   }
+
+   size = sendmsg(sock, &msg, 0);
+
+   /* errors are returned directly */
+   return size;
+}
+
+/*
+ * Receive data from a unix domain socket. If a file is sent over the socket,
+ * store it in *fd.
+ */
+ssize_t
+pg_uds_recv_with_fd(int sock, void *buf, ssize_t bufsize, int *fd)
+{
+   ssize_t     size;
+   struct msghdr   msg;
+   struct iovec    iov;
+   /* cmsg header, union for correct alignment */
+   union
+   {
+       struct cmsghdr  cmsghdr;
+       char        control[CMSG_SPACE(sizeof (int))];
+   } cmsgu;
+   struct cmsghdr  *cmsg;
+
+   Assert(fd != NULL);
+
+   iov.iov_base = buf;
+   iov.iov_len = bufsize;
+
+   msg.msg_name = NULL;
+   msg.msg_namelen = 0;
+   msg.msg_iov = &iov;
+   msg.msg_iovlen = 1;
+   msg.msg_control = cmsgu.control;
+   msg.msg_controllen = sizeof(cmsgu.control);
+
+   size = recvmsg (sock, &msg, 0);
+
+   if (size < 0)
+   {
+       *fd = -1;
+       return size;
+   }
+
+   cmsg = CMSG_FIRSTHDR(&msg);
+   if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
+   {
+       if (cmsg->cmsg_level != SOL_SOCKET)
+           elog(FATAL, "unexpected cmsg_level");
+
+       if (cmsg->cmsg_type != SCM_RIGHTS)
+           elog(FATAL, "unexpected cmsg_type");
+
+       *fd = *((int *) CMSG_DATA(cmsg));
+
+       /* FIXME: check / handle additional cmsg structures */
+   }
+   else
+       *fd = -1;
+
+   return size;
+}
index 8e7c9728f4b3c3c969d8ec15617854e51df4bb12..5e016d69a5a043825885df6bad917d015f494115 100644 (file)
@@ -143,4 +143,8 @@ extern void SyncDataDirectory(void);
 #define PG_TEMP_FILES_DIR "pgsql_tmp"
 #define PG_TEMP_FILE_PREFIX "pgsql_tmp"
 
+/* XXX; This should probably go elsewhere */
+ssize_t pg_uds_send_with_fd(int sock, void *buf, ssize_t buflen, int fd);
+ssize_t pg_uds_recv_with_fd(int sock, void *buf, ssize_t bufsize, int *fd);
+
 #endif                         /* FD_H */