1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1020 @@ 1.4 +// Copyright (c) 2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "chrome/common/ipc_channel_posix.h" 1.9 + 1.10 +#include <errno.h> 1.11 +#include <fcntl.h> 1.12 +#include <stddef.h> 1.13 +#include <unistd.h> 1.14 +#include <sys/types.h> 1.15 +#include <sys/socket.h> 1.16 +#include <sys/stat.h> 1.17 +#include <sys/un.h> 1.18 +#include <sys/uio.h> 1.19 + 1.20 +#include <string> 1.21 +#include <map> 1.22 + 1.23 +#include "base/command_line.h" 1.24 +#include "base/eintr_wrapper.h" 1.25 +#include "base/lock.h" 1.26 +#include "base/logging.h" 1.27 +#include "base/process_util.h" 1.28 +#include "base/scoped_ptr.h" 1.29 +#include "base/string_util.h" 1.30 +#include "base/singleton.h" 1.31 +#include "base/stats_counters.h" 1.32 +#include "chrome/common/chrome_switches.h" 1.33 +#include "chrome/common/file_descriptor_set_posix.h" 1.34 +#include "chrome/common/ipc_logging.h" 1.35 +#include "chrome/common/ipc_message_utils.h" 1.36 +#include "mozilla/ipc/ProtocolUtils.h" 1.37 + 1.38 +#ifdef MOZ_TASK_TRACER 1.39 +#include "GeckoTaskTracerImpl.h" 1.40 +using namespace mozilla::tasktracer; 1.41 +#endif 1.42 + 1.43 +namespace IPC { 1.44 + 1.45 +// IPC channels on Windows use named pipes (CreateNamedPipe()) with 1.46 +// channel ids as the pipe names. Channels on POSIX use anonymous 1.47 +// Unix domain sockets created via socketpair() as pipes. These don't 1.48 +// quite line up. 1.49 +// 1.50 +// When creating a child subprocess, the parent side of the fork 1.51 +// arranges it such that the initial control channel ends up on the 1.52 +// magic file descriptor kClientChannelFd in the child. Future 1.53 +// connections (file descriptors) can then be passed via that 1.54 +// connection via sendmsg(). 1.55 + 1.56 +//------------------------------------------------------------------------------ 1.57 +namespace { 1.58 + 1.59 +// The PipeMap class works around this quirk related to unit tests: 1.60 +// 1.61 +// When running as a server, we install the client socket in a 1.62 +// specific file descriptor number (@kClientChannelFd). However, we 1.63 +// also have to support the case where we are running unittests in the 1.64 +// same process. (We do not support forking without execing.) 1.65 +// 1.66 +// Case 1: normal running 1.67 +// The IPC server object will install a mapping in PipeMap from the 1.68 +// name which it was given to the client pipe. When forking the client, the 1.69 +// GetClientFileDescriptorMapping will ensure that the socket is installed in 1.70 +// the magic slot (@kClientChannelFd). The client will search for the 1.71 +// mapping, but it won't find any since we are in a new process. Thus the 1.72 +// magic fd number is returned. Once the client connects, the server will 1.73 +// close its copy of the client socket and remove the mapping. 1.74 +// 1.75 +// Case 2: unittests - client and server in the same process 1.76 +// The IPC server will install a mapping as before. The client will search 1.77 +// for a mapping and find out. It duplicates the file descriptor and 1.78 +// connects. Once the client connects, the server will close the original 1.79 +// copy of the client socket and remove the mapping. Thus, when the client 1.80 +// object closes, it will close the only remaining copy of the client socket 1.81 +// in the fd table and the server will see EOF on its side. 1.82 +// 1.83 +// TODO(port): a client process cannot connect to multiple IPC channels with 1.84 +// this scheme. 1.85 + 1.86 +class PipeMap { 1.87 + public: 1.88 + // Lookup a given channel id. Return -1 if not found. 1.89 + int Lookup(const std::string& channel_id) { 1.90 + AutoLock locked(lock_); 1.91 + 1.92 + ChannelToFDMap::const_iterator i = map_.find(channel_id); 1.93 + if (i == map_.end()) 1.94 + return -1; 1.95 + return i->second; 1.96 + } 1.97 + 1.98 + // Remove the mapping for the given channel id. No error is signaled if the 1.99 + // channel_id doesn't exist 1.100 + void Remove(const std::string& channel_id) { 1.101 + AutoLock locked(lock_); 1.102 + 1.103 + ChannelToFDMap::iterator i = map_.find(channel_id); 1.104 + if (i != map_.end()) 1.105 + map_.erase(i); 1.106 + } 1.107 + 1.108 + // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a 1.109 + // mapping if one already exists for the given channel_id 1.110 + void Insert(const std::string& channel_id, int fd) { 1.111 + AutoLock locked(lock_); 1.112 + DCHECK(fd != -1); 1.113 + 1.114 + ChannelToFDMap::const_iterator i = map_.find(channel_id); 1.115 + CHECK(i == map_.end()) << "Creating second IPC server for '" 1.116 + << channel_id 1.117 + << "' while first still exists"; 1.118 + map_[channel_id] = fd; 1.119 + } 1.120 + 1.121 + private: 1.122 + Lock lock_; 1.123 + typedef std::map<std::string, int> ChannelToFDMap; 1.124 + ChannelToFDMap map_; 1.125 +}; 1.126 + 1.127 +// This is the file descriptor number that a client process expects to find its 1.128 +// IPC socket. 1.129 +static const int kClientChannelFd = 3; 1.130 + 1.131 +// Used to map a channel name to the equivalent FD # in the client process. 1.132 +int ChannelNameToClientFD(const std::string& channel_id) { 1.133 + // See the large block comment above PipeMap for the reasoning here. 1.134 + const int fd = Singleton<PipeMap>()->Lookup(channel_id); 1.135 + if (fd != -1) 1.136 + return dup(fd); 1.137 + 1.138 + // If we don't find an entry, we assume that the correct value has been 1.139 + // inserted in the magic slot. 1.140 + return kClientChannelFd; 1.141 +} 1.142 + 1.143 +//------------------------------------------------------------------------------ 1.144 +const size_t kMaxPipeNameLength = sizeof(((sockaddr_un*)0)->sun_path); 1.145 + 1.146 +// Creates a Fifo with the specified name ready to listen on. 1.147 +bool CreateServerFifo(const std::string& pipe_name, int* server_listen_fd) { 1.148 + DCHECK(server_listen_fd); 1.149 + DCHECK_GT(pipe_name.length(), 0u); 1.150 + DCHECK_LT(pipe_name.length(), kMaxPipeNameLength); 1.151 + 1.152 + if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) { 1.153 + return false; 1.154 + } 1.155 + 1.156 + // Create socket. 1.157 + int fd = socket(AF_UNIX, SOCK_STREAM, 0); 1.158 + if (fd < 0) { 1.159 + return false; 1.160 + } 1.161 + 1.162 + // Make socket non-blocking 1.163 + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 1.164 + HANDLE_EINTR(close(fd)); 1.165 + return false; 1.166 + } 1.167 + 1.168 + // Delete any old FS instances. 1.169 + unlink(pipe_name.c_str()); 1.170 + 1.171 + // Create unix_addr structure 1.172 + struct sockaddr_un unix_addr; 1.173 + memset(&unix_addr, 0, sizeof(unix_addr)); 1.174 + unix_addr.sun_family = AF_UNIX; 1.175 + snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str()); 1.176 + size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) + 1.177 + strlen(unix_addr.sun_path) + 1; 1.178 + 1.179 + // Bind the socket. 1.180 + if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr), 1.181 + unix_addr_len) != 0) { 1.182 + HANDLE_EINTR(close(fd)); 1.183 + return false; 1.184 + } 1.185 + 1.186 + // Start listening on the socket. 1.187 + const int listen_queue_length = 1; 1.188 + if (listen(fd, listen_queue_length) != 0) { 1.189 + HANDLE_EINTR(close(fd)); 1.190 + return false; 1.191 + } 1.192 + 1.193 + *server_listen_fd = fd; 1.194 + return true; 1.195 +} 1.196 + 1.197 +// Accept a connection on a fifo. 1.198 +bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) { 1.199 + DCHECK(server_socket); 1.200 + 1.201 + int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0)); 1.202 + if (accept_fd < 0) 1.203 + return false; 1.204 + if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) { 1.205 + HANDLE_EINTR(close(accept_fd)); 1.206 + return false; 1.207 + } 1.208 + 1.209 + *server_socket = accept_fd; 1.210 + return true; 1.211 +} 1.212 + 1.213 +bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) { 1.214 + DCHECK(client_socket); 1.215 + DCHECK_LT(pipe_name.length(), kMaxPipeNameLength); 1.216 + 1.217 + // Create socket. 1.218 + int fd = socket(AF_UNIX, SOCK_STREAM, 0); 1.219 + if (fd < 0) { 1.220 + CHROMIUM_LOG(ERROR) << "fd is invalid"; 1.221 + return false; 1.222 + } 1.223 + 1.224 + // Make socket non-blocking 1.225 + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 1.226 + CHROMIUM_LOG(ERROR) << "fcntl failed"; 1.227 + HANDLE_EINTR(close(fd)); 1.228 + return false; 1.229 + } 1.230 + 1.231 + // Create server side of socket. 1.232 + struct sockaddr_un server_unix_addr; 1.233 + memset(&server_unix_addr, 0, sizeof(server_unix_addr)); 1.234 + server_unix_addr.sun_family = AF_UNIX; 1.235 + snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s", 1.236 + pipe_name.c_str()); 1.237 + size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) + 1.238 + strlen(server_unix_addr.sun_path) + 1; 1.239 + 1.240 + if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr), 1.241 + server_unix_addr_len)) != 0) { 1.242 + HANDLE_EINTR(close(fd)); 1.243 + return false; 1.244 + } 1.245 + 1.246 + *client_socket = fd; 1.247 + return true; 1.248 +} 1.249 + 1.250 +bool SetCloseOnExec(int fd) { 1.251 + int flags = fcntl(fd, F_GETFD); 1.252 + if (flags == -1) 1.253 + return false; 1.254 + 1.255 + flags |= FD_CLOEXEC; 1.256 + if (fcntl(fd, F_SETFD, flags) == -1) 1.257 + return false; 1.258 + 1.259 + return true; 1.260 +} 1.261 + 1.262 +} // namespace 1.263 +//------------------------------------------------------------------------------ 1.264 + 1.265 +Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode, 1.266 + Listener* listener) 1.267 + : factory_(this) { 1.268 + Init(mode, listener); 1.269 + uses_fifo_ = CommandLine::ForCurrentProcess()->HasSwitch(switches::kIPCUseFIFO); 1.270 + 1.271 + if (!CreatePipe(channel_id, mode)) { 1.272 + // The pipe may have been closed already. 1.273 + CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id << 1.274 + "\" in " << (mode == MODE_SERVER ? "server" : "client") << 1.275 + " mode error(" << strerror(errno) << ")."; 1.276 + } 1.277 +} 1.278 + 1.279 +Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener) 1.280 + : factory_(this) { 1.281 + Init(mode, listener); 1.282 + pipe_ = fd; 1.283 + waiting_connect_ = (MODE_SERVER == mode); 1.284 + 1.285 + EnqueueHelloMessage(); 1.286 +} 1.287 + 1.288 +void Channel::ChannelImpl::Init(Mode mode, Listener* listener) { 1.289 + mode_ = mode; 1.290 + is_blocked_on_write_ = false; 1.291 + message_send_bytes_written_ = 0; 1.292 + uses_fifo_ = false; 1.293 + server_listen_pipe_ = -1; 1.294 + pipe_ = -1; 1.295 + client_pipe_ = -1; 1.296 + listener_ = listener; 1.297 + waiting_connect_ = true; 1.298 + processing_incoming_ = false; 1.299 + closed_ = false; 1.300 +#if defined(OS_MACOSX) 1.301 + last_pending_fd_id_ = 0; 1.302 +#endif 1.303 + output_queue_length_ = 0; 1.304 +} 1.305 + 1.306 +bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id, 1.307 + Mode mode) { 1.308 + DCHECK(server_listen_pipe_ == -1 && pipe_ == -1); 1.309 + 1.310 + if (uses_fifo_) { 1.311 + // This only happens in unit tests; see the comment above PipeMap. 1.312 + // TODO(playmobil): We shouldn't need to create fifos on disk. 1.313 + // TODO(playmobil): If we do, they should be in the user data directory. 1.314 + // TODO(playmobil): Cleanup any stale fifos. 1.315 + pipe_name_ = "/var/tmp/chrome_" + WideToASCII(channel_id); 1.316 + if (mode == MODE_SERVER) { 1.317 + if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) { 1.318 + return false; 1.319 + } 1.320 + } else { 1.321 + if (!ClientConnectToFifo(pipe_name_, &pipe_)) { 1.322 + return false; 1.323 + } 1.324 + waiting_connect_ = false; 1.325 + } 1.326 + } else { 1.327 + // socketpair() 1.328 + pipe_name_ = WideToASCII(channel_id); 1.329 + if (mode == MODE_SERVER) { 1.330 + int pipe_fds[2]; 1.331 + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) { 1.332 + return false; 1.333 + } 1.334 + // Set both ends to be non-blocking. 1.335 + if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 || 1.336 + fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) { 1.337 + HANDLE_EINTR(close(pipe_fds[0])); 1.338 + HANDLE_EINTR(close(pipe_fds[1])); 1.339 + return false; 1.340 + } 1.341 + 1.342 + if (!SetCloseOnExec(pipe_fds[0]) || 1.343 + !SetCloseOnExec(pipe_fds[1])) { 1.344 + HANDLE_EINTR(close(pipe_fds[0])); 1.345 + HANDLE_EINTR(close(pipe_fds[1])); 1.346 + return false; 1.347 + } 1.348 + 1.349 + pipe_ = pipe_fds[0]; 1.350 + client_pipe_ = pipe_fds[1]; 1.351 + 1.352 + if (pipe_name_.length()) { 1.353 + Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_); 1.354 + } 1.355 + } else { 1.356 + pipe_ = ChannelNameToClientFD(pipe_name_); 1.357 + DCHECK(pipe_ > 0); 1.358 + waiting_connect_ = false; 1.359 + } 1.360 + } 1.361 + 1.362 + // Create the Hello message to be sent when Connect is called 1.363 + return EnqueueHelloMessage(); 1.364 +} 1.365 + 1.366 +/** 1.367 + * Reset the file descriptor for communication with the peer. 1.368 + */ 1.369 +void Channel::ChannelImpl::ResetFileDescriptor(int fd) { 1.370 + NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor"); 1.371 + 1.372 + EnqueueHelloMessage(); 1.373 +} 1.374 + 1.375 +bool Channel::ChannelImpl::EnqueueHelloMessage() { 1.376 + scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE, 1.377 + HELLO_MESSAGE_TYPE, 1.378 + IPC::Message::PRIORITY_NORMAL)); 1.379 + if (!msg->WriteInt(base::GetCurrentProcId())) { 1.380 + Close(); 1.381 + return false; 1.382 + } 1.383 + 1.384 + OutputQueuePush(msg.release()); 1.385 + return true; 1.386 +} 1.387 + 1.388 +static void 1.389 +ClearAndShrink(std::string& s, size_t capacity) 1.390 +{ 1.391 + // This swap trick is the closest thing C++ has to a guaranteed way to 1.392 + // shrink the capacity of a string. 1.393 + std::string tmp; 1.394 + tmp.reserve(capacity); 1.395 + s.swap(tmp); 1.396 +} 1.397 + 1.398 +bool Channel::ChannelImpl::Connect() { 1.399 + if (mode_ == MODE_SERVER && uses_fifo_) { 1.400 + if (server_listen_pipe_ == -1) { 1.401 + return false; 1.402 + } 1.403 + MessageLoopForIO::current()->WatchFileDescriptor( 1.404 + server_listen_pipe_, 1.405 + true, 1.406 + MessageLoopForIO::WATCH_READ, 1.407 + &server_listen_connection_watcher_, 1.408 + this); 1.409 + } else { 1.410 + if (pipe_ == -1) { 1.411 + return false; 1.412 + } 1.413 + MessageLoopForIO::current()->WatchFileDescriptor( 1.414 + pipe_, 1.415 + true, 1.416 + MessageLoopForIO::WATCH_READ, 1.417 + &read_watcher_, 1.418 + this); 1.419 + waiting_connect_ = false; 1.420 + } 1.421 + 1.422 + if (!waiting_connect_) 1.423 + return ProcessOutgoingMessages(); 1.424 + return true; 1.425 +} 1.426 + 1.427 +bool Channel::ChannelImpl::ProcessIncomingMessages() { 1.428 + ssize_t bytes_read = 0; 1.429 + 1.430 + struct msghdr msg = {0}; 1.431 + struct iovec iov = {input_buf_, Channel::kReadBufferSize}; 1.432 + 1.433 + msg.msg_iov = &iov; 1.434 + msg.msg_iovlen = 1; 1.435 + msg.msg_control = input_cmsg_buf_; 1.436 + 1.437 + for (;;) { 1.438 + msg.msg_controllen = sizeof(input_cmsg_buf_); 1.439 + 1.440 + if (bytes_read == 0) { 1.441 + if (pipe_ == -1) 1.442 + return false; 1.443 + 1.444 + // Read from pipe. 1.445 + // recvmsg() returns 0 if the connection has closed or EAGAIN if no data 1.446 + // is waiting on the pipe. 1.447 + bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT)); 1.448 + 1.449 + if (bytes_read < 0) { 1.450 + if (errno == EAGAIN) { 1.451 + return true; 1.452 + } else { 1.453 + CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno); 1.454 + return false; 1.455 + } 1.456 + } else if (bytes_read == 0) { 1.457 + // The pipe has closed... 1.458 + Close(); 1.459 + return false; 1.460 + } 1.461 + } 1.462 + DCHECK(bytes_read); 1.463 + 1.464 + if (client_pipe_ != -1) { 1.465 + Singleton<PipeMap>()->Remove(pipe_name_); 1.466 + HANDLE_EINTR(close(client_pipe_)); 1.467 + client_pipe_ = -1; 1.468 + } 1.469 + 1.470 + // a pointer to an array of |num_wire_fds| file descriptors from the read 1.471 + const int* wire_fds = NULL; 1.472 + unsigned num_wire_fds = 0; 1.473 + 1.474 + // walk the list of control messages and, if we find an array of file 1.475 + // descriptors, save a pointer to the array 1.476 + 1.477 + // This next if statement is to work around an OSX issue where 1.478 + // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0. 1.479 + // Here's a test case: 1.480 + // 1.481 + // int main() { 1.482 + // struct msghdr msg; 1.483 + // msg.msg_control = &msg; 1.484 + // msg.msg_controllen = 0; 1.485 + // if (CMSG_FIRSTHDR(&msg)) 1.486 + // printf("Bug found!\n"); 1.487 + // } 1.488 + if (msg.msg_controllen > 0) { 1.489 + // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0 1.490 + // and will return a pointer into nowhere. 1.491 + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; 1.492 + cmsg = CMSG_NXTHDR(&msg, cmsg)) { 1.493 + if (cmsg->cmsg_level == SOL_SOCKET && 1.494 + cmsg->cmsg_type == SCM_RIGHTS) { 1.495 + const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); 1.496 + DCHECK(payload_len % sizeof(int) == 0); 1.497 + wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); 1.498 + num_wire_fds = payload_len / 4; 1.499 + 1.500 + if (msg.msg_flags & MSG_CTRUNC) { 1.501 + CHROMIUM_LOG(ERROR) << "SCM_RIGHTS message was truncated" 1.502 + << " cmsg_len:" << cmsg->cmsg_len 1.503 + << " fd:" << pipe_; 1.504 + for (unsigned i = 0; i < num_wire_fds; ++i) 1.505 + HANDLE_EINTR(close(wire_fds[i])); 1.506 + return false; 1.507 + } 1.508 + break; 1.509 + } 1.510 + } 1.511 + } 1.512 + 1.513 + // Process messages from input buffer. 1.514 + const char *p; 1.515 + const char *overflowp; 1.516 + const char *end; 1.517 + if (input_overflow_buf_.empty()) { 1.518 + overflowp = NULL; 1.519 + p = input_buf_; 1.520 + end = p + bytes_read; 1.521 + } else { 1.522 + if (input_overflow_buf_.size() > 1.523 + static_cast<size_t>(kMaximumMessageSize - bytes_read)) { 1.524 + ClearAndShrink(input_overflow_buf_, Channel::kReadBufferSize); 1.525 + CHROMIUM_LOG(ERROR) << "IPC message is too big"; 1.526 + return false; 1.527 + } 1.528 + input_overflow_buf_.append(input_buf_, bytes_read); 1.529 + overflowp = p = input_overflow_buf_.data(); 1.530 + end = p + input_overflow_buf_.size(); 1.531 + } 1.532 + 1.533 + // A pointer to an array of |num_fds| file descriptors which includes any 1.534 + // fds that have spilled over from a previous read. 1.535 + const int* fds; 1.536 + unsigned num_fds; 1.537 + unsigned fds_i = 0; // the index of the first unused descriptor 1.538 + 1.539 + if (input_overflow_fds_.empty()) { 1.540 + fds = wire_fds; 1.541 + num_fds = num_wire_fds; 1.542 + } else { 1.543 + const size_t prev_size = input_overflow_fds_.size(); 1.544 + input_overflow_fds_.resize(prev_size + num_wire_fds); 1.545 + memcpy(&input_overflow_fds_[prev_size], wire_fds, 1.546 + num_wire_fds * sizeof(int)); 1.547 + fds = &input_overflow_fds_[0]; 1.548 + num_fds = input_overflow_fds_.size(); 1.549 + } 1.550 + 1.551 + while (p < end) { 1.552 + const char* message_tail = Message::FindNext(p, end); 1.553 + if (message_tail) { 1.554 + int len = static_cast<int>(message_tail - p); 1.555 + Message m(p, len); 1.556 + if (m.header()->num_fds) { 1.557 + // the message has file descriptors 1.558 + const char* error = NULL; 1.559 + if (m.header()->num_fds > num_fds - fds_i) { 1.560 + // the message has been completely received, but we didn't get 1.561 + // enough file descriptors. 1.562 + error = "Message needs unreceived descriptors"; 1.563 + } 1.564 + 1.565 + if (m.header()->num_fds > 1.566 + FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) { 1.567 + // There are too many descriptors in this message 1.568 + error = "Message requires an excessive number of descriptors"; 1.569 + } 1.570 + 1.571 + if (error) { 1.572 + CHROMIUM_LOG(WARNING) << error 1.573 + << " channel:" << this 1.574 + << " message-type:" << m.type() 1.575 + << " header()->num_fds:" << m.header()->num_fds 1.576 + << " num_fds:" << num_fds 1.577 + << " fds_i:" << fds_i; 1.578 + // close the existing file descriptors so that we don't leak them 1.579 + for (unsigned i = fds_i; i < num_fds; ++i) 1.580 + HANDLE_EINTR(close(fds[i])); 1.581 + input_overflow_fds_.clear(); 1.582 + // abort the connection 1.583 + return false; 1.584 + } 1.585 + 1.586 +#if defined(OS_MACOSX) 1.587 + // Send a message to the other side, indicating that we are now 1.588 + // responsible for closing the descriptor. 1.589 + Message *fdAck = new Message(MSG_ROUTING_NONE, 1.590 + RECEIVED_FDS_MESSAGE_TYPE, 1.591 + IPC::Message::PRIORITY_NORMAL); 1.592 + DCHECK(m.fd_cookie() != 0); 1.593 + fdAck->set_fd_cookie(m.fd_cookie()); 1.594 + OutputQueuePush(fdAck); 1.595 +#endif 1.596 + 1.597 + m.file_descriptor_set()->SetDescriptors( 1.598 + &fds[fds_i], m.header()->num_fds); 1.599 + fds_i += m.header()->num_fds; 1.600 + } 1.601 +#ifdef IPC_MESSAGE_DEBUG_EXTRA 1.602 + DLOG(INFO) << "received message on channel @" << this << 1.603 + " with type " << m.type(); 1.604 +#endif 1.605 + 1.606 +#ifdef MOZ_TASK_TRACER 1.607 + AutoSaveCurTraceInfo saveCurTraceInfo; 1.608 + SetCurTraceInfo(m.header()->source_event_id, 1.609 + m.header()->parent_task_id, 1.610 + m.header()->source_event_type); 1.611 +#endif 1.612 + 1.613 + if (m.routing_id() == MSG_ROUTING_NONE && 1.614 + m.type() == HELLO_MESSAGE_TYPE) { 1.615 + // The Hello message contains only the process id. 1.616 + listener_->OnChannelConnected(MessageIterator(m).NextInt()); 1.617 +#if defined(OS_MACOSX) 1.618 + } else if (m.routing_id() == MSG_ROUTING_NONE && 1.619 + m.type() == RECEIVED_FDS_MESSAGE_TYPE) { 1.620 + DCHECK(m.fd_cookie() != 0); 1.621 + CloseDescriptors(m.fd_cookie()); 1.622 +#endif 1.623 + } else { 1.624 + listener_->OnMessageReceived(m); 1.625 + } 1.626 + p = message_tail; 1.627 + } else { 1.628 + // Last message is partial. 1.629 + break; 1.630 + } 1.631 + } 1.632 + if (end == p) { 1.633 + ClearAndShrink(input_overflow_buf_, Channel::kReadBufferSize); 1.634 + } else if (!overflowp) { 1.635 + // p is from input_buf_ 1.636 + input_overflow_buf_.assign(p, end - p); 1.637 + } else if (p > overflowp) { 1.638 + // p is from input_overflow_buf_ 1.639 + input_overflow_buf_.erase(0, p - overflowp); 1.640 + } 1.641 + input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]); 1.642 + 1.643 + // When the input data buffer is empty, the overflow fds should be too. If 1.644 + // this is not the case, we probably have a rogue renderer which is trying 1.645 + // to fill our descriptor table. 1.646 + if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) { 1.647 + // We close these descriptors in Close() 1.648 + return false; 1.649 + } 1.650 + 1.651 + bytes_read = 0; // Get more data. 1.652 + } 1.653 + 1.654 + return true; 1.655 +} 1.656 + 1.657 +bool Channel::ChannelImpl::ProcessOutgoingMessages() { 1.658 + DCHECK(!waiting_connect_); // Why are we trying to send messages if there's 1.659 + // no connection? 1.660 + is_blocked_on_write_ = false; 1.661 + 1.662 + if (output_queue_.empty()) 1.663 + return true; 1.664 + 1.665 + if (pipe_ == -1) 1.666 + return false; 1.667 + 1.668 + // Write out all the messages we can till the write blocks or there are no 1.669 + // more outgoing messages. 1.670 + while (!output_queue_.empty()) { 1.671 + Message* msg = output_queue_.front(); 1.672 + 1.673 + struct msghdr msgh = {0}; 1.674 + 1.675 + static const int tmp = CMSG_SPACE(sizeof( 1.676 + int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE])); 1.677 + char buf[tmp]; 1.678 + 1.679 + if (message_send_bytes_written_ == 0 && 1.680 + !msg->file_descriptor_set()->empty()) { 1.681 + // This is the first chunk of a message which has descriptors to send 1.682 + struct cmsghdr *cmsg; 1.683 + const unsigned num_fds = msg->file_descriptor_set()->size(); 1.684 + 1.685 + if (num_fds > FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) { 1.686 + CHROMIUM_LOG(FATAL) << "Too many file descriptors!"; 1.687 + // This should not be reached. 1.688 + return false; 1.689 + } 1.690 + 1.691 + msgh.msg_control = buf; 1.692 + msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); 1.693 + cmsg = CMSG_FIRSTHDR(&msgh); 1.694 + cmsg->cmsg_level = SOL_SOCKET; 1.695 + cmsg->cmsg_type = SCM_RIGHTS; 1.696 + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); 1.697 + msg->file_descriptor_set()->GetDescriptors( 1.698 + reinterpret_cast<int*>(CMSG_DATA(cmsg))); 1.699 + msgh.msg_controllen = cmsg->cmsg_len; 1.700 + 1.701 + msg->header()->num_fds = num_fds; 1.702 +#if defined(OS_MACOSX) 1.703 + msg->set_fd_cookie(++last_pending_fd_id_); 1.704 +#endif 1.705 + } 1.706 +#ifdef MOZ_TASK_TRACER 1.707 + GetCurTraceInfo(&msg->header()->source_event_id, 1.708 + &msg->header()->parent_task_id, 1.709 + &msg->header()->source_event_type); 1.710 +#endif 1.711 + 1.712 + size_t amt_to_write = msg->size() - message_send_bytes_written_; 1.713 + DCHECK(amt_to_write != 0); 1.714 + const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + 1.715 + message_send_bytes_written_; 1.716 + 1.717 + struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write}; 1.718 + msgh.msg_iov = &iov; 1.719 + msgh.msg_iovlen = 1; 1.720 + 1.721 + ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT)); 1.722 +#if !defined(OS_MACOSX) 1.723 + // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE 1.724 + // message. 1.725 + if (bytes_written > 0) 1.726 + msg->file_descriptor_set()->CommitAll(); 1.727 +#endif 1.728 + 1.729 + if (bytes_written < 0 && errno != EAGAIN) { 1.730 + CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno); 1.731 + return false; 1.732 + } 1.733 + 1.734 + if (static_cast<size_t>(bytes_written) != amt_to_write) { 1.735 + if (bytes_written > 0) { 1.736 + // If write() fails with EAGAIN then bytes_written will be -1. 1.737 + message_send_bytes_written_ += bytes_written; 1.738 + } 1.739 + 1.740 + // Tell libevent to call us back once things are unblocked. 1.741 + is_blocked_on_write_ = true; 1.742 + MessageLoopForIO::current()->WatchFileDescriptor( 1.743 + pipe_, 1.744 + false, // One shot 1.745 + MessageLoopForIO::WATCH_WRITE, 1.746 + &write_watcher_, 1.747 + this); 1.748 + return true; 1.749 + } else { 1.750 + message_send_bytes_written_ = 0; 1.751 + 1.752 +#if defined(OS_MACOSX) 1.753 + if (!msg->file_descriptor_set()->empty()) 1.754 + pending_fds_.push_back(PendingDescriptors(msg->fd_cookie(), 1.755 + msg->file_descriptor_set())); 1.756 +#endif 1.757 + 1.758 + // Message sent OK! 1.759 +#ifdef IPC_MESSAGE_DEBUG_EXTRA 1.760 + DLOG(INFO) << "sent message @" << msg << " on channel @" << this << 1.761 + " with type " << msg->type(); 1.762 +#endif 1.763 + OutputQueuePop(); 1.764 + delete msg; 1.765 + } 1.766 + } 1.767 + return true; 1.768 +} 1.769 + 1.770 +bool Channel::ChannelImpl::Send(Message* message) { 1.771 +#ifdef IPC_MESSAGE_DEBUG_EXTRA 1.772 + DLOG(INFO) << "sending message @" << message << " on channel @" << this 1.773 + << " with type " << message->type() 1.774 + << " (" << output_queue_.size() << " in queue)"; 1.775 +#endif 1.776 + 1.777 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.778 + Logging::current()->OnSendMessage(message, L""); 1.779 +#endif 1.780 + 1.781 + // If the channel has been closed, ProcessOutgoingMessages() is never going 1.782 + // to pop anything off output_queue; output_queue will only get emptied when 1.783 + // the channel is destructed. We might as well delete message now, instead 1.784 + // of waiting for the channel to be destructed. 1.785 + if (closed_) { 1.786 + if (mozilla::ipc::LoggingEnabled()) { 1.787 + fprintf(stderr, "Can't send message %s, because this channel is closed.\n", 1.788 + message->name()); 1.789 + } 1.790 + delete message; 1.791 + return false; 1.792 + } 1.793 + 1.794 + OutputQueuePush(message); 1.795 + if (!waiting_connect_) { 1.796 + if (!is_blocked_on_write_) { 1.797 + if (!ProcessOutgoingMessages()) 1.798 + return false; 1.799 + } 1.800 + } 1.801 + 1.802 + return true; 1.803 +} 1.804 + 1.805 +void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd, 1.806 + int *dest_fd) const { 1.807 + DCHECK(mode_ == MODE_SERVER); 1.808 + *src_fd = client_pipe_; 1.809 + *dest_fd = kClientChannelFd; 1.810 +} 1.811 + 1.812 +void Channel::ChannelImpl::CloseClientFileDescriptor() { 1.813 + if (client_pipe_ != -1) { 1.814 + Singleton<PipeMap>()->Remove(pipe_name_); 1.815 + HANDLE_EINTR(close(client_pipe_)); 1.816 + client_pipe_ = -1; 1.817 + } 1.818 +} 1.819 + 1.820 +// Called by libevent when we can read from th pipe without blocking. 1.821 +void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { 1.822 + bool send_server_hello_msg = false; 1.823 + if (waiting_connect_ && mode_ == MODE_SERVER) { 1.824 + // In the case of a socketpair() the server starts listening on its end 1.825 + // of the pipe in Connect(). 1.826 + DCHECK(uses_fifo_); 1.827 + 1.828 + if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) { 1.829 + Close(); 1.830 + } 1.831 + 1.832 + // No need to watch the listening socket any longer since only one client 1.833 + // can connect. So unregister with libevent. 1.834 + server_listen_connection_watcher_.StopWatchingFileDescriptor(); 1.835 + 1.836 + // Start watching our end of the socket. 1.837 + MessageLoopForIO::current()->WatchFileDescriptor( 1.838 + pipe_, 1.839 + true, 1.840 + MessageLoopForIO::WATCH_READ, 1.841 + &read_watcher_, 1.842 + this); 1.843 + 1.844 + waiting_connect_ = false; 1.845 + send_server_hello_msg = true; 1.846 + } 1.847 + 1.848 + if (!waiting_connect_ && fd == pipe_) { 1.849 + if (!ProcessIncomingMessages()) { 1.850 + Close(); 1.851 + listener_->OnChannelError(); 1.852 + } 1.853 + } 1.854 + 1.855 + // If we're a server and handshaking, then we want to make sure that we 1.856 + // only send our handshake message after we've processed the client's. 1.857 + // This gives us a chance to kill the client if the incoming handshake 1.858 + // is invalid. 1.859 + if (send_server_hello_msg) { 1.860 + // This should be our first write so there's no chance we can block here... 1.861 + DCHECK(is_blocked_on_write_ == false); 1.862 + ProcessOutgoingMessages(); 1.863 + } 1.864 +} 1.865 + 1.866 +#if defined(OS_MACOSX) 1.867 +void Channel::ChannelImpl::CloseDescriptors(uint32_t pending_fd_id) 1.868 +{ 1.869 + DCHECK(pending_fd_id != 0); 1.870 + for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin(); 1.871 + i != pending_fds_.end(); 1.872 + i++) { 1.873 + if ((*i).id == pending_fd_id) { 1.874 + (*i).fds->CommitAll(); 1.875 + pending_fds_.erase(i); 1.876 + return; 1.877 + } 1.878 + } 1.879 + DCHECK(false) << "pending_fd_id not in our list!"; 1.880 +} 1.881 +#endif 1.882 + 1.883 +void Channel::ChannelImpl::OutputQueuePush(Message* msg) 1.884 +{ 1.885 + output_queue_.push(msg); 1.886 + output_queue_length_++; 1.887 +} 1.888 + 1.889 +void Channel::ChannelImpl::OutputQueuePop() 1.890 +{ 1.891 + output_queue_.pop(); 1.892 + output_queue_length_--; 1.893 +} 1.894 + 1.895 +// Called by libevent when we can write to the pipe without blocking. 1.896 +void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { 1.897 + if (!ProcessOutgoingMessages()) { 1.898 + Close(); 1.899 + listener_->OnChannelError(); 1.900 + } 1.901 +} 1.902 + 1.903 +void Channel::ChannelImpl::Close() { 1.904 + // Close can be called multiple times, so we need to make sure we're 1.905 + // idempotent. 1.906 + 1.907 + // Unregister libevent for the listening socket and close it. 1.908 + server_listen_connection_watcher_.StopWatchingFileDescriptor(); 1.909 + 1.910 + if (server_listen_pipe_ != -1) { 1.911 + HANDLE_EINTR(close(server_listen_pipe_)); 1.912 + server_listen_pipe_ = -1; 1.913 + } 1.914 + 1.915 + // Unregister libevent for the FIFO and close it. 1.916 + read_watcher_.StopWatchingFileDescriptor(); 1.917 + write_watcher_.StopWatchingFileDescriptor(); 1.918 + if (pipe_ != -1) { 1.919 + HANDLE_EINTR(close(pipe_)); 1.920 + pipe_ = -1; 1.921 + } 1.922 + if (client_pipe_ != -1) { 1.923 + Singleton<PipeMap>()->Remove(pipe_name_); 1.924 + HANDLE_EINTR(close(client_pipe_)); 1.925 + client_pipe_ = -1; 1.926 + } 1.927 + 1.928 + if (uses_fifo_) { 1.929 + // Unlink the FIFO 1.930 + unlink(pipe_name_.c_str()); 1.931 + } 1.932 + 1.933 + while (!output_queue_.empty()) { 1.934 + Message* m = output_queue_.front(); 1.935 + OutputQueuePop(); 1.936 + delete m; 1.937 + } 1.938 + 1.939 + // Close any outstanding, received file descriptors 1.940 + for (std::vector<int>::iterator 1.941 + i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) { 1.942 + HANDLE_EINTR(close(*i)); 1.943 + } 1.944 + input_overflow_fds_.clear(); 1.945 + 1.946 +#if defined(OS_MACOSX) 1.947 + for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin(); 1.948 + i != pending_fds_.end(); 1.949 + i++) { 1.950 + (*i).fds->CommitAll(); 1.951 + } 1.952 + pending_fds_.clear(); 1.953 +#endif 1.954 + 1.955 + closed_ = true; 1.956 +} 1.957 + 1.958 +bool Channel::ChannelImpl::Unsound_IsClosed() const 1.959 +{ 1.960 + return closed_; 1.961 +} 1.962 + 1.963 +uint32_t Channel::ChannelImpl::Unsound_NumQueuedMessages() const 1.964 +{ 1.965 + return output_queue_length_; 1.966 +} 1.967 + 1.968 +//------------------------------------------------------------------------------ 1.969 +// Channel's methods simply call through to ChannelImpl. 1.970 +Channel::Channel(const std::wstring& channel_id, Mode mode, 1.971 + Listener* listener) 1.972 + : channel_impl_(new ChannelImpl(channel_id, mode, listener)) { 1.973 +} 1.974 + 1.975 +Channel::Channel(int fd, Mode mode, Listener* listener) 1.976 + : channel_impl_(new ChannelImpl(fd, mode, listener)) { 1.977 +} 1.978 + 1.979 +Channel::~Channel() { 1.980 + delete channel_impl_; 1.981 +} 1.982 + 1.983 +bool Channel::Connect() { 1.984 + return channel_impl_->Connect(); 1.985 +} 1.986 + 1.987 +void Channel::Close() { 1.988 + channel_impl_->Close(); 1.989 +} 1.990 + 1.991 +Channel::Listener* Channel::set_listener(Listener* listener) { 1.992 + return channel_impl_->set_listener(listener); 1.993 +} 1.994 + 1.995 +bool Channel::Send(Message* message) { 1.996 + return channel_impl_->Send(message); 1.997 +} 1.998 + 1.999 +void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const { 1.1000 + return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd); 1.1001 +} 1.1002 + 1.1003 +void Channel::ResetFileDescriptor(int fd) { 1.1004 + channel_impl_->ResetFileDescriptor(fd); 1.1005 +} 1.1006 + 1.1007 +int Channel::GetFileDescriptor() const { 1.1008 + return channel_impl_->GetFileDescriptor(); 1.1009 +} 1.1010 + 1.1011 +void Channel::CloseClientFileDescriptor() { 1.1012 + channel_impl_->CloseClientFileDescriptor(); 1.1013 +} 1.1014 + 1.1015 +bool Channel::Unsound_IsClosed() const { 1.1016 + return channel_impl_->Unsound_IsClosed(); 1.1017 +} 1.1018 + 1.1019 +uint32_t Channel::Unsound_NumQueuedMessages() const { 1.1020 + return channel_impl_->Unsound_NumQueuedMessages(); 1.1021 +} 1.1022 + 1.1023 +} // namespace IPC