fd_share.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <cstring>
  15. #include <cstdlib>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <sys/uio.h>
  19. #include <errno.h>
  20. #include <stdlib.h> // for malloc and free
  21. #include <unistd.h>
  22. #include "fd_share.h"
  23. namespace isc {
  24. namespace util {
  25. namespace io {
  26. namespace {
  27. // Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
  28. // In order to ensure as much portability as possible, we provide wrapper
  29. // functions of these macros.
  30. // Note that cmsg_space() could run slow on OSes that do not have
  31. // CMSG_SPACE.
  32. inline socklen_t
  33. cmsg_len(const socklen_t len) {
  34. #ifdef CMSG_LEN
  35. return (CMSG_LEN(len));
  36. #else
  37. // Cast NULL so that any pointer arithmetic performed by CMSG_DATA
  38. // is correct.
  39. const uintptr_t hdrlen = (uintptr_t)CMSG_DATA(((struct cmsghdr*)NULL));
  40. return (hdrlen + len);
  41. #endif
  42. }
  43. inline socklen_t
  44. cmsg_space(const socklen_t len) {
  45. #ifdef CMSG_SPACE
  46. return (CMSG_SPACE(len));
  47. #else
  48. struct msghdr msg;
  49. struct cmsghdr* cmsgp;
  50. // XXX: The buffer length is an ad hoc value, but should be enough
  51. // in a practical sense.
  52. char dummybuf[sizeof(struct cmsghdr) + 1024];
  53. memset(&msg, 0, sizeof(msg));
  54. msg.msg_control = dummybuf;
  55. msg.msg_controllen = sizeof(dummybuf);
  56. cmsgp = (struct cmsghdr*)dummybuf;
  57. cmsgp->cmsg_len = cmsg_len(len);
  58. cmsgp = CMSG_NXTHDR(&msg, cmsgp);
  59. if (cmsgp != NULL) {
  60. return ((char*)cmsgp - (char*)msg.msg_control);
  61. } else {
  62. return (0);
  63. }
  64. #endif // CMSG_SPACE
  65. }
  66. }
  67. int
  68. recv_fd(const int sock) {
  69. struct msghdr msghdr;
  70. struct iovec iov_dummy;
  71. unsigned char dummy_data;
  72. iov_dummy.iov_base = &dummy_data;
  73. iov_dummy.iov_len = sizeof(dummy_data);
  74. msghdr.msg_name = NULL;
  75. msghdr.msg_namelen = 0;
  76. msghdr.msg_iov = &iov_dummy;
  77. msghdr.msg_iovlen = 1;
  78. msghdr.msg_flags = 0;
  79. msghdr.msg_controllen = cmsg_space(sizeof(int));
  80. msghdr.msg_control = malloc(msghdr.msg_controllen);
  81. if (msghdr.msg_control == NULL) {
  82. return (FD_SYSTEM_ERROR);
  83. }
  84. const int cc = recvmsg(sock, &msghdr, 0);
  85. if (cc <= 0) {
  86. free(msghdr.msg_control);
  87. if (cc == 0) {
  88. errno = ECONNRESET;
  89. }
  90. return (FD_SYSTEM_ERROR);
  91. }
  92. const struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
  93. int fd = FD_OTHER_ERROR;
  94. if (cmsg != NULL && cmsg->cmsg_len == cmsg_len(sizeof(int)) &&
  95. cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
  96. std::memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
  97. }
  98. free(msghdr.msg_control);
  99. // It is strange, but the call can return the same file descriptor as
  100. // one returned previously, even if that one is not closed yet. So,
  101. // we just re-number every one we get, so they are unique.
  102. int new_fd(dup(fd));
  103. if (close(fd) == -1 || new_fd == -1) {
  104. return (FD_SYSTEM_ERROR);
  105. }
  106. return (new_fd);
  107. }
  108. int
  109. send_fd(const int sock, const int fd) {
  110. struct msghdr msghdr;
  111. struct iovec iov_dummy;
  112. unsigned char dummy_data = 0;
  113. iov_dummy.iov_base = &dummy_data;
  114. iov_dummy.iov_len = sizeof(dummy_data);
  115. msghdr.msg_name = NULL;
  116. msghdr.msg_namelen = 0;
  117. msghdr.msg_iov = &iov_dummy;
  118. msghdr.msg_iovlen = 1;
  119. msghdr.msg_flags = 0;
  120. msghdr.msg_controllen = cmsg_space(sizeof(int));
  121. msghdr.msg_control = malloc(msghdr.msg_controllen);
  122. if (msghdr.msg_control == NULL) {
  123. return (FD_OTHER_ERROR);
  124. }
  125. struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
  126. cmsg->cmsg_len = cmsg_len(sizeof(int));
  127. cmsg->cmsg_level = SOL_SOCKET;
  128. cmsg->cmsg_type = SCM_RIGHTS;
  129. std::memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
  130. const int ret = sendmsg(sock, &msghdr, 0);
  131. free(msghdr.msg_control);
  132. return (ret >= 0 ? 0 : FD_SYSTEM_ERROR);
  133. }
  134. } // End for namespace io
  135. } // End for namespace util
  136. } // End for namespace isc