From: Andres Freund Date: Mon, 21 May 2018 22:43:30 +0000 (-0700) Subject: Add functions to send/receive data & FD over a unix domain socket. X-Git-Url: http://git.postgresql.org/gitweb/delmail?a=commitdiff_plain;h=aa533828e6164731006dab92665fa92b7b058d6f;p=users%2Fandresfreund%2Fpostgres.git Add functions to send/receive data & FD over a unix domain socket. 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: --- diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 441f18dcf5..65e46483a4 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -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; +} diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index 8e7c9728f4..5e016d69a5 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -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 */