|
@@ -14,7 +14,9 @@
|
|
|
|
|
|
// $Id$
|
|
|
|
|
|
-#include <stdlib.h>
|
|
|
+#include <cstring>
|
|
|
+#include <cstdlib>
|
|
|
+
|
|
|
#include <sys/types.h>
|
|
|
#include <sys/socket.h>
|
|
|
#include <sys/uio.h>
|
|
@@ -23,98 +25,100 @@
|
|
|
namespace isc {
|
|
|
namespace xfr {
|
|
|
|
|
|
-#define FD_BUFFER_CREATE(n) \
|
|
|
- struct { \
|
|
|
- struct cmsghdr h; \
|
|
|
- int fd[n]; \
|
|
|
+namespace {
|
|
|
+// Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
|
|
|
+// In order to ensure as much portability as possible, we provide wrapper
|
|
|
+// functions of these macros.
|
|
|
+// Note that cmsg_space() could run slow on OSes that do not have
|
|
|
+// CMSG_SPACE.
|
|
|
+inline socklen_t
|
|
|
+cmsg_space(socklen_t len) {
|
|
|
+#ifdef CMSG_SPACE
|
|
|
+ return (CMSG_SPACE(len));
|
|
|
+#else
|
|
|
+ struct msghdr msg;
|
|
|
+ struct cmsghdr* cmsgp;
|
|
|
+ // XXX: The buffer length is an ad hoc value, but should be enough
|
|
|
+ // in a practical sense.
|
|
|
+ char dummybuf[sizeof(struct cmsghdr) + 1024];
|
|
|
+
|
|
|
+ memset(&msg, 0, sizeof(msg));
|
|
|
+ msg.msg_control = dummybuf;
|
|
|
+ msg.msg_controllen = sizeof(dummybuf);
|
|
|
+
|
|
|
+ cmsgp = (struct cmsghdr*)dummybuf;
|
|
|
+ cmsgp->cmsg_len = cmsg_len(len);
|
|
|
+
|
|
|
+ cmsgp = CMSG_NXTHDR(&msg, cmsgp);
|
|
|
+ if (cmsgp != NULL) {
|
|
|
+ return ((char*)cmsgp - (char*)msg.msg_control);
|
|
|
+ } else {
|
|
|
+ return (0);
|
|
|
}
|
|
|
+#endif // CMSG_SPACE
|
|
|
+}
|
|
|
+}
|
|
|
|
|
|
-namespace {
|
|
|
int
|
|
|
-send_fds_with_buffer(const int sock, const int* fds, const unsigned n_fds,
|
|
|
- void* buffer)
|
|
|
-{
|
|
|
+recv_fd(const int sock) {
|
|
|
struct msghdr msghdr;
|
|
|
- char nothing = '!';
|
|
|
- struct iovec nothing_ptr;
|
|
|
- struct cmsghdr* cmsg;
|
|
|
+ struct iovec iov_dummy;
|
|
|
+ unsigned char dummy_data;
|
|
|
|
|
|
- nothing_ptr.iov_base = ¬hing;
|
|
|
- nothing_ptr.iov_len = 1;
|
|
|
+ iov_dummy.iov_base = &dummy_data;
|
|
|
+ iov_dummy.iov_len = sizeof(dummy_data);
|
|
|
msghdr.msg_name = NULL;
|
|
|
msghdr.msg_namelen = 0;
|
|
|
- msghdr.msg_iov = ¬hing_ptr;
|
|
|
+ msghdr.msg_iov = &iov_dummy;
|
|
|
msghdr.msg_iovlen = 1;
|
|
|
msghdr.msg_flags = 0;
|
|
|
- msghdr.msg_control = buffer;
|
|
|
- msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds;
|
|
|
- cmsg = CMSG_FIRSTHDR(&msghdr);
|
|
|
- cmsg->cmsg_len = msghdr.msg_controllen;
|
|
|
- cmsg->cmsg_level = SOL_SOCKET;
|
|
|
- cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
- for (int i = 0; i < n_fds; ++i) {
|
|
|
- ((int *)CMSG_DATA(cmsg))[i] = fds[i];
|
|
|
+ msghdr.msg_controllen = cmsg_space(sizeof(int));
|
|
|
+ msghdr.msg_control = malloc(msghdr.msg_controllen);
|
|
|
+ if (msghdr.msg_control == NULL) {
|
|
|
+ return (-1);
|
|
|
}
|
|
|
|
|
|
- const int ret = sendmsg(sock, &msghdr, 0);
|
|
|
- return (ret >= 0 ? 0 : -1);
|
|
|
+ if (recvmsg(sock, &msghdr, 0) < 0) {
|
|
|
+ free(msghdr.msg_control);
|
|
|
+ return (-1);
|
|
|
+ }
|
|
|
+ const struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
|
|
|
+ int fd = -1;
|
|
|
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
+ fd = *(const int *)CMSG_DATA(cmsg);
|
|
|
+ }
|
|
|
+ free(msghdr.msg_control);
|
|
|
+ return (fd);
|
|
|
}
|
|
|
|
|
|
int
|
|
|
-recv_fds_with_buffer(const int sock, int* fds, const unsigned n_fds,
|
|
|
- void* buffer)
|
|
|
-{
|
|
|
+send_fd(const int sock, const int fd) {
|
|
|
struct msghdr msghdr;
|
|
|
- char nothing;
|
|
|
- struct iovec nothing_ptr;
|
|
|
- struct cmsghdr *cmsg;
|
|
|
- int i;
|
|
|
+ struct iovec iov_dummy;
|
|
|
+ unsigned char dummy_data = 0;
|
|
|
|
|
|
- nothing_ptr.iov_base = ¬hing;
|
|
|
- nothing_ptr.iov_len = 1;
|
|
|
+ iov_dummy.iov_base = &dummy_data;
|
|
|
+ iov_dummy.iov_len = sizeof(dummy_data);
|
|
|
msghdr.msg_name = NULL;
|
|
|
msghdr.msg_namelen = 0;
|
|
|
- msghdr.msg_iov = ¬hing_ptr;
|
|
|
+ msghdr.msg_iov = &iov_dummy;
|
|
|
msghdr.msg_iovlen = 1;
|
|
|
msghdr.msg_flags = 0;
|
|
|
- msghdr.msg_control = buffer;
|
|
|
- msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds;
|
|
|
- cmsg = CMSG_FIRSTHDR(&msghdr);
|
|
|
- cmsg->cmsg_len = msghdr.msg_controllen;
|
|
|
- cmsg->cmsg_level = SOL_SOCKET;
|
|
|
- cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
- for (i = 0; i < n_fds; i++) {
|
|
|
- ((int *)CMSG_DATA(cmsg))[i] = -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (recvmsg(sock, &msghdr, 0) < 0) {
|
|
|
+ msghdr.msg_controllen = cmsg_space(sizeof(int));
|
|
|
+ msghdr.msg_control = malloc(msghdr.msg_controllen);
|
|
|
+ if (msghdr.msg_control == NULL) {
|
|
|
return (-1);
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < n_fds; i++) {
|
|
|
- fds[i] = ((int *)CMSG_DATA(cmsg))[i];
|
|
|
- }
|
|
|
-
|
|
|
- return ((msghdr.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int));
|
|
|
-}
|
|
|
-}
|
|
|
-
|
|
|
-int
|
|
|
-recv_fd(const int sock) {
|
|
|
- FD_BUFFER_CREATE(1) buffer;
|
|
|
- int fd = 0;
|
|
|
- if (recv_fds_with_buffer(sock, &fd, 1, &buffer) == -1) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- return fd;
|
|
|
-}
|
|
|
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
|
|
|
+ cmsg->cmsg_len = msghdr.msg_controllen;
|
|
|
+ cmsg->cmsg_level = SOL_SOCKET;
|
|
|
+ cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
+ *(int *)CMSG_DATA(cmsg) = fd;
|
|
|
|
|
|
-int
|
|
|
-send_fd(const int sock, const int fd) {
|
|
|
- FD_BUFFER_CREATE(1) buffer;
|
|
|
- int ret = send_fds_with_buffer(sock, &fd, 1, &buffer);
|
|
|
- return ((ret < 0) ? -1 : ret);
|
|
|
+ const int ret = sendmsg(sock, &msghdr, 0);
|
|
|
+ free(msghdr.msg_control);
|
|
|
+ return (ret >= 0 ? 0 : -1);
|
|
|
}
|
|
|
|
|
|
} // End for namespace xfr
|