Chromium Code Reviews| 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 |