Branch data Line data Source code
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 : :
15 : : #include <cstring>
16 : : #include <cstdlib>
17 : :
18 : : #include <sys/types.h>
19 : : #include <sys/socket.h>
20 : : #include <sys/uio.h>
21 : : #include <errno.h>
22 : : #include <stdlib.h> // for malloc and free
23 : : #include <unistd.h>
24 : : #include "fd_share.h"
25 : :
26 : : namespace isc {
27 : : namespace util {
28 : : namespace io {
29 : :
30 : : namespace {
31 : : // Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
32 : : // In order to ensure as much portability as possible, we provide wrapper
33 : : // functions of these macros.
34 : : // Note that cmsg_space() could run slow on OSes that do not have
35 : : // CMSG_SPACE.
36 : : inline socklen_t
37 : : cmsg_len(const socklen_t len) {
38 : : #ifdef CMSG_LEN
39 : : return (CMSG_LEN(len));
40 : : #else
41 : : // Cast NULL so that any pointer arithmetic performed by CMSG_DATA
42 : : // is correct.
43 : : const uintptr_t hdrlen = (uintptr_t)CMSG_DATA(((struct cmsghdr*)NULL));
44 : : return (hdrlen + len);
45 : : #endif
46 : : }
47 : :
48 : : inline socklen_t
49 : : cmsg_space(const socklen_t len) {
50 : : #ifdef CMSG_SPACE
51 : : return (CMSG_SPACE(len));
52 : : #else
53 : : struct msghdr msg;
54 : : struct cmsghdr* cmsgp;
55 : : // XXX: The buffer length is an ad hoc value, but should be enough
56 : : // in a practical sense.
57 : : char dummybuf[sizeof(struct cmsghdr) + 1024];
58 : :
59 : : memset(&msg, 0, sizeof(msg));
60 : : msg.msg_control = dummybuf;
61 : : msg.msg_controllen = sizeof(dummybuf);
62 : :
63 : : cmsgp = (struct cmsghdr*)dummybuf;
64 : : cmsgp->cmsg_len = cmsg_len(len);
65 : :
66 : : cmsgp = CMSG_NXTHDR(&msg, cmsgp);
67 : : if (cmsgp != NULL) {
68 : : return ((char*)cmsgp - (char*)msg.msg_control);
69 : : } else {
70 : : return (0);
71 : : }
72 : : #endif // CMSG_SPACE
73 : : }
74 : : }
75 : :
76 : : int
77 : 46 : recv_fd(const int sock) {
78 : : struct msghdr msghdr;
79 : : struct iovec iov_dummy;
80 : : unsigned char dummy_data;
81 : :
82 : 46 : iov_dummy.iov_base = &dummy_data;
83 : 46 : iov_dummy.iov_len = sizeof(dummy_data);
84 : 46 : msghdr.msg_name = NULL;
85 : 46 : msghdr.msg_namelen = 0;
86 : 46 : msghdr.msg_iov = &iov_dummy;
87 : 46 : msghdr.msg_iovlen = 1;
88 : 46 : msghdr.msg_flags = 0;
89 : 46 : msghdr.msg_controllen = cmsg_space(sizeof(int));
90 : 46 : msghdr.msg_control = malloc(msghdr.msg_controllen);
91 [ + - ]: 46 : if (msghdr.msg_control == NULL) {
92 : : return (FD_SYSTEM_ERROR);
93 : : }
94 : :
95 : 46 : const int cc = recvmsg(sock, &msghdr, 0);
96 [ + + ]: 46 : if (cc <= 0) {
97 : 2 : free(msghdr.msg_control);
98 [ + - ]: 2 : if (cc == 0) {
99 : 2 : errno = ECONNRESET;
100 : : }
101 : : return (FD_SYSTEM_ERROR);
102 : : }
103 [ + + ]: 44 : const struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
104 : 44 : int fd = FD_OTHER_ERROR;
105 [ + + ][ + - ]: 44 : if (cmsg != NULL && cmsg->cmsg_len == cmsg_len(sizeof(int)) &&
[ - + ][ + + ]
106 : : cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
107 : 42 : std::memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
108 : : }
109 : 44 : free(msghdr.msg_control);
110 : : // It is strange, but the call can return the same file descriptor as
111 : : // one returned previously, even if that one is not closed yet. So,
112 : : // we just re-number every one we get, so they are unique.
113 : 44 : int new_fd(dup(fd));
114 : 44 : int close_error(close(fd));
115 [ + + ]: 44 : if (close_error == -1 || new_fd == -1) {
116 : : // We need to return an error, because something failed. But in case
117 : : // it was the previous close, we at least try to close the duped FD.
118 [ - + ]: 2 : if (new_fd != -1) {
119 : 46 : close(new_fd); // If this fails, nothing but returning error can't
120 : : // be done and we are doing that anyway.
121 : : }
122 : : return (FD_SYSTEM_ERROR);
123 : : }
124 : : return (new_fd);
125 : : }
126 : :
127 : : int
128 : 51 : send_fd(const int sock, const int fd) {
129 : : struct msghdr msghdr;
130 : : struct iovec iov_dummy;
131 : 51 : unsigned char dummy_data = 0;
132 : :
133 : 51 : iov_dummy.iov_base = &dummy_data;
134 : 51 : iov_dummy.iov_len = sizeof(dummy_data);
135 : 51 : msghdr.msg_name = NULL;
136 : 51 : msghdr.msg_namelen = 0;
137 : 51 : msghdr.msg_iov = &iov_dummy;
138 : 51 : msghdr.msg_iovlen = 1;
139 : 51 : msghdr.msg_flags = 0;
140 : 51 : msghdr.msg_controllen = cmsg_space(sizeof(int));
141 : 51 : msghdr.msg_control = malloc(msghdr.msg_controllen);
142 [ + - ]: 51 : if (msghdr.msg_control == NULL) {
143 : : return (FD_OTHER_ERROR);
144 : : }
145 : :
146 [ + - ]: 51 : struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
147 : 51 : cmsg->cmsg_len = cmsg_len(sizeof(int));
148 : 51 : cmsg->cmsg_level = SOL_SOCKET;
149 : 51 : cmsg->cmsg_type = SCM_RIGHTS;
150 : 51 : std::memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
151 : :
152 : 51 : const int ret = sendmsg(sock, &msghdr, 0);
153 : 51 : free(msghdr.msg_control);
154 [ + + ]: 51 : return (ret >= 0 ? 0 : FD_SYSTEM_ERROR);
155 : : }
156 : :
157 : : } // End for namespace io
158 : : } // End for namespace util
159 : : } // End for namespace isc
|