OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/posix/unix_domain_socket_linux.h" | 5 #include "base/posix/unix_domain_socket_linux.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <sys/socket.h> | 8 #include <sys/socket.h> |
9 #include <sys/uio.h> | 9 #include <sys/uio.h> |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/pickle.h" | 13 #include "base/pickle.h" |
14 #include "base/posix/eintr_wrapper.h" | 14 #include "base/posix/eintr_wrapper.h" |
15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
16 | 16 |
17 const size_t UnixDomainSocket::kMaxFileDescriptors = 16; | 17 const size_t UnixDomainSocket::kMaxFileDescriptors = 16; |
18 | 18 |
19 // static | 19 // static |
20 bool UnixDomainSocket::EnableReceiveProcessId(int fd) { | |
21 const int enable = 1; | |
22 return setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)) == 0; | |
23 } | |
24 | |
25 // static | |
20 bool UnixDomainSocket::SendMsg(int fd, | 26 bool UnixDomainSocket::SendMsg(int fd, |
21 const void* buf, | 27 const void* buf, |
22 size_t length, | 28 size_t length, |
23 const std::vector<int>& fds) { | 29 const std::vector<int>& fds) { |
24 struct msghdr msg = {}; | 30 struct msghdr msg = {}; |
25 struct iovec iov = { const_cast<void*>(buf), length }; | 31 struct iovec iov = { const_cast<void*>(buf), length }; |
26 msg.msg_iov = &iov; | 32 msg.msg_iov = &iov; |
27 msg.msg_iovlen = 1; | 33 msg.msg_iovlen = 1; |
28 | 34 |
29 char* control_buffer = NULL; | 35 char* control_buffer = NULL; |
(...skipping 21 matching lines...) Expand all Loading... | |
51 const bool ret = static_cast<ssize_t>(length) == r; | 57 const bool ret = static_cast<ssize_t>(length) == r; |
52 delete[] control_buffer; | 58 delete[] control_buffer; |
53 return ret; | 59 return ret; |
54 } | 60 } |
55 | 61 |
56 // static | 62 // static |
57 ssize_t UnixDomainSocket::RecvMsg(int fd, | 63 ssize_t UnixDomainSocket::RecvMsg(int fd, |
58 void* buf, | 64 void* buf, |
59 size_t length, | 65 size_t length, |
60 std::vector<int>* fds) { | 66 std::vector<int>* fds) { |
61 return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds); | 67 return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL); |
62 } | 68 } |
63 | 69 |
64 // static | 70 // static |
71 ssize_t UnixDomainSocket::RecvMsgWithPid(int fd, | |
72 void* buf, | |
73 size_t length, | |
74 std::vector<int>* fds, | |
75 base::ProcessId* pid) { | |
76 return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid); | |
77 } | |
78 | |
79 // static | |
65 ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd, | 80 ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd, |
66 void* buf, | 81 void* buf, |
67 size_t length, | 82 size_t length, |
68 int flags, | 83 int flags, |
69 std::vector<int>* fds) { | 84 std::vector<int>* fds, |
85 base::ProcessId* out_pid) { | |
70 fds->clear(); | 86 fds->clear(); |
71 | 87 |
72 struct msghdr msg = {}; | 88 struct msghdr msg = {}; |
73 struct iovec iov = { buf, length }; | 89 struct iovec iov = { buf, length }; |
74 msg.msg_iov = &iov; | 90 msg.msg_iov = &iov; |
75 msg.msg_iovlen = 1; | 91 msg.msg_iovlen = 1; |
76 | 92 |
77 char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)]; | 93 char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors) + |
94 CMSG_SPACE(sizeof(struct ucred))]; | |
78 msg.msg_control = control_buffer; | 95 msg.msg_control = control_buffer; |
79 msg.msg_controllen = sizeof(control_buffer); | 96 msg.msg_controllen = sizeof(control_buffer); |
80 | 97 |
81 const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags)); | 98 const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags)); |
82 if (r == -1) | 99 if (r == -1) |
83 return -1; | 100 return -1; |
84 | 101 |
85 int* wire_fds = NULL; | 102 int* wire_fds = NULL; |
86 unsigned wire_fds_len = 0; | 103 unsigned wire_fds_len = 0; |
104 base::ProcessId pid = -1; | |
87 | 105 |
88 if (msg.msg_controllen > 0) { | 106 if (msg.msg_controllen > 0) { |
89 struct cmsghdr* cmsg; | 107 struct cmsghdr* cmsg; |
90 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { | 108 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
109 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); | |
jln (very slow on Chromium)
2014/04/24 18:32:58
Ohh my, this looks like it's ripe for rewrite (in
mdempsky
2014/04/24 19:00:34
ACK
| |
91 if (cmsg->cmsg_level == SOL_SOCKET && | 110 if (cmsg->cmsg_level == SOL_SOCKET && |
92 cmsg->cmsg_type == SCM_RIGHTS) { | 111 cmsg->cmsg_type == SCM_RIGHTS) { |
93 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); | |
94 DCHECK(payload_len % sizeof(int) == 0); | 112 DCHECK(payload_len % sizeof(int) == 0); |
113 DCHECK(wire_fds == NULL); | |
95 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); | 114 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); |
96 wire_fds_len = payload_len / sizeof(int); | 115 wire_fds_len = payload_len / sizeof(int); |
97 break; | 116 } |
117 if (cmsg->cmsg_level == SOL_SOCKET && | |
118 cmsg->cmsg_type == SCM_CREDENTIALS) { | |
119 DCHECK(payload_len == sizeof(struct ucred)); | |
120 DCHECK(pid == -1); | |
121 pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid; | |
98 } | 122 } |
99 } | 123 } |
100 } | 124 } |
101 | 125 |
102 if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) { | 126 if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) { |
103 for (unsigned i = 0; i < wire_fds_len; ++i) | 127 for (unsigned i = 0; i < wire_fds_len; ++i) |
104 close(wire_fds[i]); | 128 close(wire_fds[i]); |
105 errno = EMSGSIZE; | 129 errno = EMSGSIZE; |
106 return -1; | 130 return -1; |
107 } | 131 } |
108 | 132 |
109 if (wire_fds) { | 133 if (wire_fds) { |
110 fds->resize(wire_fds_len); | 134 fds->resize(wire_fds_len); |
111 memcpy(vector_as_array(fds), wire_fds, sizeof(int) * wire_fds_len); | 135 memcpy(vector_as_array(fds), wire_fds, sizeof(int) * wire_fds_len); |
112 } | 136 } |
113 | 137 |
138 if (out_pid) { | |
139 DCHECK(pid != -1); | |
140 *out_pid = pid; | |
141 } | |
142 | |
114 return r; | 143 return r; |
115 } | 144 } |
116 | 145 |
117 // static | 146 // static |
118 ssize_t UnixDomainSocket::SendRecvMsg(int fd, | 147 ssize_t UnixDomainSocket::SendRecvMsg(int fd, |
119 uint8_t* reply, | 148 uint8_t* reply, |
120 unsigned max_reply_len, | 149 unsigned max_reply_len, |
121 int* result_fd, | 150 int* result_fd, |
122 const Pickle& request) { | 151 const Pickle& request) { |
123 return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len, | 152 return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len, |
(...skipping 20 matching lines...) Expand all Loading... | |
144 if (!SendMsg(fd, request.data(), request.size(), fd_vector)) { | 173 if (!SendMsg(fd, request.data(), request.size(), fd_vector)) { |
145 close(fds[0]); | 174 close(fds[0]); |
146 close(fds[1]); | 175 close(fds[1]); |
147 return -1; | 176 return -1; |
148 } | 177 } |
149 close(fds[1]); | 178 close(fds[1]); |
150 | 179 |
151 fd_vector.clear(); | 180 fd_vector.clear(); |
152 // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the | 181 // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the |
153 // sender might get a SIGPIPE. | 182 // sender might get a SIGPIPE. |
154 const ssize_t reply_len = RecvMsgWithFlags(fds[0], reply, max_reply_len, | 183 const ssize_t reply_len = RecvMsgWithFlags( |
155 recvmsg_flags, &fd_vector); | 184 fds[0], reply, max_reply_len, recvmsg_flags, &fd_vector, NULL); |
156 close(fds[0]); | 185 close(fds[0]); |
157 if (reply_len == -1) | 186 if (reply_len == -1) |
158 return -1; | 187 return -1; |
159 | 188 |
160 if ((!fd_vector.empty() && result_fd == NULL) || fd_vector.size() > 1) { | 189 if ((!fd_vector.empty() && result_fd == NULL) || fd_vector.size() > 1) { |
161 for (std::vector<int>::const_iterator | 190 for (std::vector<int>::const_iterator |
162 i = fd_vector.begin(); i != fd_vector.end(); ++i) { | 191 i = fd_vector.begin(); i != fd_vector.end(); ++i) { |
163 close(*i); | 192 close(*i); |
164 } | 193 } |
165 | 194 |
166 NOTREACHED(); | 195 NOTREACHED(); |
167 | 196 |
168 return -1; | 197 return -1; |
169 } | 198 } |
170 | 199 |
171 if (result_fd) | 200 if (result_fd) |
172 *result_fd = fd_vector.empty() ? -1 : fd_vector[0]; | 201 *result_fd = fd_vector.empty() ? -1 : fd_vector[0]; |
173 | 202 |
174 return reply_len; | 203 return reply_len; |
175 } | 204 } |
OLD | NEW |