| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/common/ipc_channel_posix.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 #include <fcntl.h> | |
| 9 #include <stddef.h> | |
| 10 #include <sys/types.h> | |
| 11 #include <sys/socket.h> | |
| 12 #include <sys/stat.h> | |
| 13 #include <sys/un.h> | |
| 14 | |
| 15 #include <string> | |
| 16 #include <map> | |
| 17 | |
| 18 #include "base/command_line.h" | |
| 19 #include "base/eintr_wrapper.h" | |
| 20 #include "base/global_descriptors_posix.h" | |
| 21 #include "base/lock.h" | |
| 22 #include "base/logging.h" | |
| 23 #include "base/process_util.h" | |
| 24 #include "base/scoped_ptr.h" | |
| 25 #include "base/string_util.h" | |
| 26 #include "base/singleton.h" | |
| 27 #include "base/stats_counters.h" | |
| 28 #include "chrome/common/chrome_counters.h" | |
| 29 #include "chrome/common/chrome_descriptors.h" | |
| 30 #include "chrome/common/chrome_switches.h" | |
| 31 #include "chrome/common/file_descriptor_set_posix.h" | |
| 32 #include "chrome/common/ipc_logging.h" | |
| 33 #include "chrome/common/ipc_message_utils.h" | |
| 34 | |
| 35 namespace IPC { | |
| 36 | |
| 37 // IPC channels on Windows use named pipes (CreateNamedPipe()) with | |
| 38 // channel ids as the pipe names. Channels on POSIX use anonymous | |
| 39 // Unix domain sockets created via socketpair() as pipes. These don't | |
| 40 // quite line up. | |
| 41 // | |
| 42 // When creating a child subprocess, the parent side of the fork | |
| 43 // arranges it such that the initial control channel ends up on the | |
| 44 // magic file descriptor kPrimaryIPCChannel in the child. Future | |
| 45 // connections (file descriptors) can then be passed via that | |
| 46 // connection via sendmsg(). | |
| 47 | |
| 48 //------------------------------------------------------------------------------ | |
| 49 namespace { | |
| 50 | |
| 51 // The PipeMap class works around this quirk related to unit tests: | |
| 52 // | |
| 53 // When running as a server, we install the client socket in a | |
| 54 // specific file descriptor number (@kPrimaryIPCChannel). However, we | |
| 55 // also have to support the case where we are running unittests in the | |
| 56 // same process. (We do not support forking without execing.) | |
| 57 // | |
| 58 // Case 1: normal running | |
| 59 // The IPC server object will install a mapping in PipeMap from the | |
| 60 // name which it was given to the client pipe. When forking the client, the | |
| 61 // GetClientFileDescriptorMapping will ensure that the socket is installed in | |
| 62 // the magic slot (@kPrimaryIPCChannel). The client will search for the | |
| 63 // mapping, but it won't find any since we are in a new process. Thus the | |
| 64 // magic fd number is returned. Once the client connects, the server will | |
| 65 // close its copy of the client socket and remove the mapping. | |
| 66 // | |
| 67 // Case 2: unittests - client and server in the same process | |
| 68 // The IPC server will install a mapping as before. The client will search | |
| 69 // for a mapping and find out. It duplicates the file descriptor and | |
| 70 // connects. Once the client connects, the server will close the original | |
| 71 // copy of the client socket and remove the mapping. Thus, when the client | |
| 72 // object closes, it will close the only remaining copy of the client socket | |
| 73 // in the fd table and the server will see EOF on its side. | |
| 74 // | |
| 75 // TODO(port): a client process cannot connect to multiple IPC channels with | |
| 76 // this scheme. | |
| 77 | |
| 78 class PipeMap { | |
| 79 public: | |
| 80 // Lookup a given channel id. Return -1 if not found. | |
| 81 int Lookup(const std::string& channel_id) { | |
| 82 AutoLock locked(lock_); | |
| 83 | |
| 84 ChannelToFDMap::const_iterator i = map_.find(channel_id); | |
| 85 if (i == map_.end()) | |
| 86 return -1; | |
| 87 return i->second; | |
| 88 } | |
| 89 | |
| 90 // Remove the mapping for the given channel id. No error is signaled if the | |
| 91 // channel_id doesn't exist | |
| 92 void RemoveAndClose(const std::string& channel_id) { | |
| 93 AutoLock locked(lock_); | |
| 94 | |
| 95 ChannelToFDMap::iterator i = map_.find(channel_id); | |
| 96 if (i != map_.end()) { | |
| 97 HANDLE_EINTR(close(i->second)); | |
| 98 map_.erase(i); | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a | |
| 103 // mapping if one already exists for the given channel_id | |
| 104 void Insert(const std::string& channel_id, int fd) { | |
| 105 AutoLock locked(lock_); | |
| 106 DCHECK(fd != -1); | |
| 107 | |
| 108 ChannelToFDMap::const_iterator i = map_.find(channel_id); | |
| 109 CHECK(i == map_.end()) << "Creating second IPC server (fd " << fd << ") " | |
| 110 << "for '" << channel_id << "' while first " | |
| 111 << "(fd " << i->second << ") still exists"; | |
| 112 map_[channel_id] = fd; | |
| 113 } | |
| 114 | |
| 115 private: | |
| 116 Lock lock_; | |
| 117 typedef std::map<std::string, int> ChannelToFDMap; | |
| 118 ChannelToFDMap map_; | |
| 119 }; | |
| 120 | |
| 121 // Used to map a channel name to the equivalent FD # in the current process. | |
| 122 // Returns -1 if the channel is unknown. | |
| 123 int ChannelNameToFD(const std::string& channel_id) { | |
| 124 // See the large block comment above PipeMap for the reasoning here. | |
| 125 const int fd = Singleton<PipeMap>()->Lookup(channel_id); | |
| 126 | |
| 127 if (fd != -1) { | |
| 128 int dup_fd = dup(fd); | |
| 129 if (dup_fd < 0) | |
| 130 LOG(FATAL) << "dup(" << fd << "): " << strerror(errno); | |
| 131 return dup_fd; | |
| 132 } | |
| 133 | |
| 134 return fd; | |
| 135 } | |
| 136 | |
| 137 //------------------------------------------------------------------------------ | |
| 138 sockaddr_un sizecheck; | |
| 139 const size_t kMaxPipeNameLength = sizeof(sizecheck.sun_path); | |
| 140 | |
| 141 // Creates a Fifo with the specified name ready to listen on. | |
| 142 bool CreateServerFifo(const std::string& pipe_name, int* server_listen_fd) { | |
| 143 DCHECK(server_listen_fd); | |
| 144 DCHECK_GT(pipe_name.length(), 0u); | |
| 145 DCHECK_LT(pipe_name.length(), kMaxPipeNameLength); | |
| 146 | |
| 147 if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) { | |
| 148 return false; | |
| 149 } | |
| 150 | |
| 151 // Create socket. | |
| 152 int fd = socket(AF_UNIX, SOCK_STREAM, 0); | |
| 153 if (fd < 0) { | |
| 154 return false; | |
| 155 } | |
| 156 | |
| 157 // Make socket non-blocking | |
| 158 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { | |
| 159 HANDLE_EINTR(close(fd)); | |
| 160 return false; | |
| 161 } | |
| 162 | |
| 163 // Delete any old FS instances. | |
| 164 unlink(pipe_name.c_str()); | |
| 165 | |
| 166 // Create unix_addr structure | |
| 167 struct sockaddr_un unix_addr; | |
| 168 memset(&unix_addr, 0, sizeof(unix_addr)); | |
| 169 unix_addr.sun_family = AF_UNIX; | |
| 170 snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str()); | |
| 171 size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) + | |
| 172 strlen(unix_addr.sun_path) + 1; | |
| 173 | |
| 174 // Bind the socket. | |
| 175 if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr), | |
| 176 unix_addr_len) != 0) { | |
| 177 HANDLE_EINTR(close(fd)); | |
| 178 return false; | |
| 179 } | |
| 180 | |
| 181 // Start listening on the socket. | |
| 182 const int listen_queue_length = 1; | |
| 183 if (listen(fd, listen_queue_length) != 0) { | |
| 184 HANDLE_EINTR(close(fd)); | |
| 185 return false; | |
| 186 } | |
| 187 | |
| 188 *server_listen_fd = fd; | |
| 189 return true; | |
| 190 } | |
| 191 | |
| 192 // Accept a connection on a fifo. | |
| 193 bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) { | |
| 194 DCHECK(server_socket); | |
| 195 | |
| 196 int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0)); | |
| 197 if (accept_fd < 0) | |
| 198 return false; | |
| 199 if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) { | |
| 200 HANDLE_EINTR(close(accept_fd)); | |
| 201 return false; | |
| 202 } | |
| 203 | |
| 204 *server_socket = accept_fd; | |
| 205 return true; | |
| 206 } | |
| 207 | |
| 208 bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) { | |
| 209 DCHECK(client_socket); | |
| 210 DCHECK_LT(pipe_name.length(), kMaxPipeNameLength); | |
| 211 | |
| 212 // Create socket. | |
| 213 int fd = socket(AF_UNIX, SOCK_STREAM, 0); | |
| 214 if (fd < 0) { | |
| 215 LOG(ERROR) << "fd is invalid"; | |
| 216 return false; | |
| 217 } | |
| 218 | |
| 219 // Make socket non-blocking | |
| 220 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { | |
| 221 LOG(ERROR) << "fcntl failed"; | |
| 222 HANDLE_EINTR(close(fd)); | |
| 223 return false; | |
| 224 } | |
| 225 | |
| 226 // Create server side of socket. | |
| 227 struct sockaddr_un server_unix_addr; | |
| 228 memset(&server_unix_addr, 0, sizeof(server_unix_addr)); | |
| 229 server_unix_addr.sun_family = AF_UNIX; | |
| 230 snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s", | |
| 231 pipe_name.c_str()); | |
| 232 size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) + | |
| 233 strlen(server_unix_addr.sun_path) + 1; | |
| 234 | |
| 235 if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr), | |
| 236 server_unix_addr_len)) != 0) { | |
| 237 HANDLE_EINTR(close(fd)); | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 *client_socket = fd; | |
| 242 return true; | |
| 243 } | |
| 244 | |
| 245 } // namespace | |
| 246 //------------------------------------------------------------------------------ | |
| 247 | |
| 248 Channel::ChannelImpl::ChannelImpl(const std::string& channel_id, Mode mode, | |
| 249 Listener* listener) | |
| 250 : mode_(mode), | |
| 251 is_blocked_on_write_(false), | |
| 252 message_send_bytes_written_(0), | |
| 253 uses_fifo_(CommandLine::ForCurrentProcess()->HasSwitch( | |
| 254 switches::kIPCUseFIFO)), | |
| 255 server_listen_pipe_(-1), | |
| 256 pipe_(-1), | |
| 257 client_pipe_(-1), | |
| 258 listener_(listener), | |
| 259 waiting_connect_(true), | |
| 260 processing_incoming_(false), | |
| 261 factory_(this) { | |
| 262 if (!CreatePipe(channel_id, mode)) { | |
| 263 // The pipe may have been closed already. | |
| 264 LOG(WARNING) << "Unable to create pipe named \"" << channel_id << | |
| 265 "\" in " << (mode == MODE_SERVER ? "server" : "client") << | |
| 266 " mode error(" << strerror(errno) << ")."; | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 // static | |
| 271 void AddChannelSocket(const std::string& name, int socket) { | |
| 272 Singleton<PipeMap>()->Insert(name, socket); | |
| 273 } | |
| 274 | |
| 275 // static | |
| 276 void RemoveAndCloseChannelSocket(const std::string& name) { | |
| 277 Singleton<PipeMap>()->RemoveAndClose(name); | |
| 278 } | |
| 279 | |
| 280 // static | |
| 281 bool SocketPair(int* fd1, int* fd2) { | |
| 282 int pipe_fds[2]; | |
| 283 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) { | |
| 284 LOG(ERROR) << "socketpair(): " << strerror(errno); | |
| 285 return false; | |
| 286 } | |
| 287 | |
| 288 // Set both ends to be non-blocking. | |
| 289 if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 || | |
| 290 fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) { | |
| 291 LOG(ERROR) << "fcntl(O_NONBLOCK): " << strerror(errno); | |
| 292 HANDLE_EINTR(close(pipe_fds[0])); | |
| 293 HANDLE_EINTR(close(pipe_fds[1])); | |
| 294 return false; | |
| 295 } | |
| 296 | |
| 297 *fd1 = pipe_fds[0]; | |
| 298 *fd2 = pipe_fds[1]; | |
| 299 | |
| 300 return true; | |
| 301 } | |
| 302 | |
| 303 bool Channel::ChannelImpl::CreatePipe(const std::string& channel_id, | |
| 304 Mode mode) { | |
| 305 DCHECK(server_listen_pipe_ == -1 && pipe_ == -1); | |
| 306 | |
| 307 if (uses_fifo_) { | |
| 308 // This only happens in unit tests; see the comment above PipeMap. | |
| 309 // TODO(playmobil): We shouldn't need to create fifos on disk. | |
| 310 // TODO(playmobil): If we do, they should be in the user data directory. | |
| 311 // TODO(playmobil): Cleanup any stale fifos. | |
| 312 pipe_name_ = "/var/tmp/chrome_" + channel_id; | |
| 313 if (mode == MODE_SERVER) { | |
| 314 if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) { | |
| 315 return false; | |
| 316 } | |
| 317 } else { | |
| 318 if (!ClientConnectToFifo(pipe_name_, &pipe_)) { | |
| 319 return false; | |
| 320 } | |
| 321 waiting_connect_ = false; | |
| 322 } | |
| 323 } else { | |
| 324 // This is the normal (non-unit-test) case, where we're using sockets. | |
| 325 // Three possible cases: | |
| 326 // 1) It's for a channel we already have a pipe for; reuse it. | |
| 327 // 2) It's the initial IPC channel: | |
| 328 // 2a) Server side: create the pipe. | |
| 329 // 2b) Client side: Pull the pipe out of the GlobalDescriptors set. | |
| 330 pipe_name_ = channel_id; | |
| 331 pipe_ = ChannelNameToFD(pipe_name_); | |
| 332 if (pipe_ < 0) { | |
| 333 // Initial IPC channel. | |
| 334 if (mode == MODE_SERVER) { | |
| 335 if (!SocketPair(&pipe_, &client_pipe_)) | |
| 336 return false; | |
| 337 AddChannelSocket(pipe_name_, client_pipe_); | |
| 338 } else { | |
| 339 pipe_ = Singleton<base::GlobalDescriptors>()->Get(kPrimaryIPCChannel); | |
| 340 } | |
| 341 } else { | |
| 342 waiting_connect_ = false; | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 // Create the Hello message to be sent when Connect is called | |
| 347 scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE, | |
| 348 HELLO_MESSAGE_TYPE, | |
| 349 IPC::Message::PRIORITY_NORMAL)); | |
| 350 if (!msg->WriteInt(base::GetCurrentProcId())) { | |
| 351 Close(); | |
| 352 return false; | |
| 353 } | |
| 354 | |
| 355 output_queue_.push(msg.release()); | |
| 356 return true; | |
| 357 } | |
| 358 | |
| 359 bool Channel::ChannelImpl::Connect() { | |
| 360 if (mode_ == MODE_SERVER && uses_fifo_) { | |
| 361 if (server_listen_pipe_ == -1) { | |
| 362 return false; | |
| 363 } | |
| 364 MessageLoopForIO::current()->WatchFileDescriptor( | |
| 365 server_listen_pipe_, | |
| 366 true, | |
| 367 MessageLoopForIO::WATCH_READ, | |
| 368 &server_listen_connection_watcher_, | |
| 369 this); | |
| 370 } else { | |
| 371 if (pipe_ == -1) { | |
| 372 return false; | |
| 373 } | |
| 374 MessageLoopForIO::current()->WatchFileDescriptor( | |
| 375 pipe_, | |
| 376 true, | |
| 377 MessageLoopForIO::WATCH_READ, | |
| 378 &read_watcher_, | |
| 379 this); | |
| 380 waiting_connect_ = false; | |
| 381 } | |
| 382 | |
| 383 if (!waiting_connect_) | |
| 384 return ProcessOutgoingMessages(); | |
| 385 return true; | |
| 386 } | |
| 387 | |
| 388 bool Channel::ChannelImpl::ProcessIncomingMessages() { | |
| 389 ssize_t bytes_read = 0; | |
| 390 | |
| 391 struct msghdr msg = {0}; | |
| 392 struct iovec iov = {input_buf_, Channel::kReadBufferSize}; | |
| 393 | |
| 394 msg.msg_iov = &iov; | |
| 395 msg.msg_iovlen = 1; | |
| 396 msg.msg_control = input_cmsg_buf_; | |
| 397 | |
| 398 for (;;) { | |
| 399 msg.msg_controllen = sizeof(input_cmsg_buf_); | |
| 400 | |
| 401 if (bytes_read == 0) { | |
| 402 if (pipe_ == -1) | |
| 403 return false; | |
| 404 | |
| 405 // Read from pipe. | |
| 406 // recvmsg() returns 0 if the connection has closed or EAGAIN if no data | |
| 407 // is waiting on the pipe. | |
| 408 bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT)); | |
| 409 | |
| 410 if (bytes_read < 0) { | |
| 411 if (errno == EAGAIN) { | |
| 412 return true; | |
| 413 #if defined(OS_MACOSX) | |
| 414 } else if (errno == EPERM) { | |
| 415 // On OSX, reading from a pipe with no listener returns EPERM | |
| 416 // treat this as a special case to prevent spurious error messages | |
| 417 // to the console. | |
| 418 return false; | |
| 419 #endif // defined(OS_MACOSX) | |
| 420 } else { | |
| 421 LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno); | |
| 422 return false; | |
| 423 } | |
| 424 } else if (bytes_read == 0) { | |
| 425 // The pipe has closed... | |
| 426 Close(); | |
| 427 return false; | |
| 428 } | |
| 429 } | |
| 430 DCHECK(bytes_read); | |
| 431 | |
| 432 if (client_pipe_ != -1) { | |
| 433 Singleton<PipeMap>()->RemoveAndClose(pipe_name_); | |
| 434 client_pipe_ = -1; | |
| 435 } | |
| 436 | |
| 437 // a pointer to an array of |num_wire_fds| file descriptors from the read | |
| 438 const int* wire_fds = NULL; | |
| 439 unsigned num_wire_fds = 0; | |
| 440 | |
| 441 // walk the list of control messages and, if we find an array of file | |
| 442 // descriptors, save a pointer to the array | |
| 443 | |
| 444 // This next if statement is to work around an OSX issue where | |
| 445 // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0. | |
| 446 // Here's a test case: | |
| 447 // | |
| 448 // int main() { | |
| 449 // struct msghdr msg; | |
| 450 // msg.msg_control = &msg; | |
| 451 // msg.msg_controllen = 0; | |
| 452 // if (CMSG_FIRSTHDR(&msg)) | |
| 453 // printf("Bug found!\n"); | |
| 454 // } | |
| 455 if (msg.msg_controllen > 0) { | |
| 456 // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0 | |
| 457 // and will return a pointer into nowhere. | |
| 458 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; | |
| 459 cmsg = CMSG_NXTHDR(&msg, cmsg)) { | |
| 460 if (cmsg->cmsg_level == SOL_SOCKET && | |
| 461 cmsg->cmsg_type == SCM_RIGHTS) { | |
| 462 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); | |
| 463 DCHECK(payload_len % sizeof(int) == 0); | |
| 464 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); | |
| 465 num_wire_fds = payload_len / 4; | |
| 466 | |
| 467 if (msg.msg_flags & MSG_CTRUNC) { | |
| 468 LOG(ERROR) << "SCM_RIGHTS message was truncated" | |
| 469 << " cmsg_len:" << cmsg->cmsg_len | |
| 470 << " fd:" << pipe_; | |
| 471 for (unsigned i = 0; i < num_wire_fds; ++i) | |
| 472 HANDLE_EINTR(close(wire_fds[i])); | |
| 473 return false; | |
| 474 } | |
| 475 break; | |
| 476 } | |
| 477 } | |
| 478 } | |
| 479 | |
| 480 // Process messages from input buffer. | |
| 481 const char *p; | |
| 482 const char *end; | |
| 483 if (input_overflow_buf_.empty()) { | |
| 484 p = input_buf_; | |
| 485 end = p + bytes_read; | |
| 486 } else { | |
| 487 if (input_overflow_buf_.size() > | |
| 488 static_cast<size_t>(kMaximumMessageSize - bytes_read)) { | |
| 489 input_overflow_buf_.clear(); | |
| 490 LOG(ERROR) << "IPC message is too big"; | |
| 491 return false; | |
| 492 } | |
| 493 input_overflow_buf_.append(input_buf_, bytes_read); | |
| 494 p = input_overflow_buf_.data(); | |
| 495 end = p + input_overflow_buf_.size(); | |
| 496 } | |
| 497 | |
| 498 // A pointer to an array of |num_fds| file descriptors which includes any | |
| 499 // fds that have spilled over from a previous read. | |
| 500 const int* fds; | |
| 501 unsigned num_fds; | |
| 502 unsigned fds_i = 0; // the index of the first unused descriptor | |
| 503 | |
| 504 if (input_overflow_fds_.empty()) { | |
| 505 fds = wire_fds; | |
| 506 num_fds = num_wire_fds; | |
| 507 } else { | |
| 508 const size_t prev_size = input_overflow_fds_.size(); | |
| 509 input_overflow_fds_.resize(prev_size + num_wire_fds); | |
| 510 memcpy(&input_overflow_fds_[prev_size], wire_fds, | |
| 511 num_wire_fds * sizeof(int)); | |
| 512 fds = &input_overflow_fds_[0]; | |
| 513 num_fds = input_overflow_fds_.size(); | |
| 514 } | |
| 515 | |
| 516 while (p < end) { | |
| 517 const char* message_tail = Message::FindNext(p, end); | |
| 518 if (message_tail) { | |
| 519 int len = static_cast<int>(message_tail - p); | |
| 520 Message m(p, len); | |
| 521 if (m.header()->num_fds) { | |
| 522 // the message has file descriptors | |
| 523 const char* error = NULL; | |
| 524 if (m.header()->num_fds > num_fds - fds_i) { | |
| 525 // the message has been completely received, but we didn't get | |
| 526 // enough file descriptors. | |
| 527 error = "Message needs unreceived descriptors"; | |
| 528 } | |
| 529 | |
| 530 if (m.header()->num_fds > | |
| 531 FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) { | |
| 532 // There are too many descriptors in this message | |
| 533 error = "Message requires an excessive number of descriptors"; | |
| 534 } | |
| 535 | |
| 536 if (error) { | |
| 537 LOG(WARNING) << error | |
| 538 << " channel:" << this | |
| 539 << " message-type:" << m.type() | |
| 540 << " header()->num_fds:" << m.header()->num_fds | |
| 541 << " num_fds:" << num_fds | |
| 542 << " fds_i:" << fds_i; | |
| 543 // close the existing file descriptors so that we don't leak them | |
| 544 for (unsigned i = fds_i; i < num_fds; ++i) | |
| 545 HANDLE_EINTR(close(fds[i])); | |
| 546 input_overflow_fds_.clear(); | |
| 547 // abort the connection | |
| 548 return false; | |
| 549 } | |
| 550 | |
| 551 m.file_descriptor_set()->SetDescriptors( | |
| 552 &fds[fds_i], m.header()->num_fds); | |
| 553 fds_i += m.header()->num_fds; | |
| 554 } | |
| 555 #ifdef IPC_MESSAGE_DEBUG_EXTRA | |
| 556 DLOG(INFO) << "received message on channel @" << this << | |
| 557 " with type " << m.type(); | |
| 558 #endif | |
| 559 if (m.routing_id() == MSG_ROUTING_NONE && | |
| 560 m.type() == HELLO_MESSAGE_TYPE) { | |
| 561 // The Hello message contains only the process id. | |
| 562 listener_->OnChannelConnected(MessageIterator(m).NextInt()); | |
| 563 } else { | |
| 564 listener_->OnMessageReceived(m); | |
| 565 } | |
| 566 p = message_tail; | |
| 567 } else { | |
| 568 // Last message is partial. | |
| 569 break; | |
| 570 } | |
| 571 } | |
| 572 input_overflow_buf_.assign(p, end - p); | |
| 573 input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]); | |
| 574 | |
| 575 // When the input data buffer is empty, the overflow fds should be too. If | |
| 576 // this is not the case, we probably have a rogue renderer which is trying | |
| 577 // to fill our descriptor table. | |
| 578 if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) { | |
| 579 // We close these descriptors in Close() | |
| 580 return false; | |
| 581 } | |
| 582 | |
| 583 bytes_read = 0; // Get more data. | |
| 584 } | |
| 585 | |
| 586 return true; | |
| 587 } | |
| 588 | |
| 589 bool Channel::ChannelImpl::ProcessOutgoingMessages() { | |
| 590 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | |
| 591 // no connection? | |
| 592 is_blocked_on_write_ = false; | |
| 593 | |
| 594 if (output_queue_.empty()) | |
| 595 return true; | |
| 596 | |
| 597 if (pipe_ == -1) | |
| 598 return false; | |
| 599 | |
| 600 // Write out all the messages we can till the write blocks or there are no | |
| 601 // more outgoing messages. | |
| 602 while (!output_queue_.empty()) { | |
| 603 Message* msg = output_queue_.front(); | |
| 604 | |
| 605 size_t amt_to_write = msg->size() - message_send_bytes_written_; | |
| 606 DCHECK(amt_to_write != 0); | |
| 607 const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + | |
| 608 message_send_bytes_written_; | |
| 609 | |
| 610 struct msghdr msgh = {0}; | |
| 611 struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write}; | |
| 612 msgh.msg_iov = &iov; | |
| 613 msgh.msg_iovlen = 1; | |
| 614 char buf[CMSG_SPACE( | |
| 615 sizeof(int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]))]; | |
| 616 | |
| 617 if (message_send_bytes_written_ == 0 && | |
| 618 !msg->file_descriptor_set()->empty()) { | |
| 619 // This is the first chunk of a message which has descriptors to send | |
| 620 struct cmsghdr *cmsg; | |
| 621 const unsigned num_fds = msg->file_descriptor_set()->size(); | |
| 622 | |
| 623 DCHECK_LE(num_fds, FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE); | |
| 624 | |
| 625 msgh.msg_control = buf; | |
| 626 msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); | |
| 627 cmsg = CMSG_FIRSTHDR(&msgh); | |
| 628 cmsg->cmsg_level = SOL_SOCKET; | |
| 629 cmsg->cmsg_type = SCM_RIGHTS; | |
| 630 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); | |
| 631 msg->file_descriptor_set()->GetDescriptors( | |
| 632 reinterpret_cast<int*>(CMSG_DATA(cmsg))); | |
| 633 msgh.msg_controllen = cmsg->cmsg_len; | |
| 634 | |
| 635 msg->header()->num_fds = num_fds; | |
| 636 } | |
| 637 | |
| 638 ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT)); | |
| 639 if (bytes_written > 0) | |
| 640 msg->file_descriptor_set()->CommitAll(); | |
| 641 | |
| 642 if (bytes_written < 0 && errno != EAGAIN) { | |
| 643 #if defined(OS_MACOSX) | |
| 644 // On OSX writing to a pipe with no listener returns EPERM. | |
| 645 if (errno == EPERM) { | |
| 646 Close(); | |
| 647 return false; | |
| 648 } | |
| 649 #endif // OS_MACOSX | |
| 650 LOG(ERROR) << "pipe error on " << pipe_ << ": " << strerror(errno); | |
| 651 return false; | |
| 652 } | |
| 653 | |
| 654 if (static_cast<size_t>(bytes_written) != amt_to_write) { | |
| 655 if (bytes_written > 0) { | |
| 656 // If write() fails with EAGAIN then bytes_written will be -1. | |
| 657 message_send_bytes_written_ += bytes_written; | |
| 658 } | |
| 659 | |
| 660 // Tell libevent to call us back once things are unblocked. | |
| 661 is_blocked_on_write_ = true; | |
| 662 MessageLoopForIO::current()->WatchFileDescriptor( | |
| 663 pipe_, | |
| 664 false, // One shot | |
| 665 MessageLoopForIO::WATCH_WRITE, | |
| 666 &write_watcher_, | |
| 667 this); | |
| 668 return true; | |
| 669 } else { | |
| 670 message_send_bytes_written_ = 0; | |
| 671 | |
| 672 // Message sent OK! | |
| 673 #ifdef IPC_MESSAGE_DEBUG_EXTRA | |
| 674 DLOG(INFO) << "sent message @" << msg << " on channel @" << this << | |
| 675 " with type " << msg->type(); | |
| 676 #endif | |
| 677 output_queue_.pop(); | |
| 678 delete msg; | |
| 679 } | |
| 680 } | |
| 681 return true; | |
| 682 } | |
| 683 | |
| 684 bool Channel::ChannelImpl::Send(Message* message) { | |
| 685 chrome::Counters::ipc_send_counter().Increment(); | |
| 686 #ifdef IPC_MESSAGE_DEBUG_EXTRA | |
| 687 DLOG(INFO) << "sending message @" << message << " on channel @" << this | |
| 688 << " with type " << message->type() | |
| 689 << " (" << output_queue_.size() << " in queue)"; | |
| 690 #endif | |
| 691 | |
| 692 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 693 Logging::current()->OnSendMessage(message, ""); | |
| 694 #endif | |
| 695 | |
| 696 output_queue_.push(message); | |
| 697 if (!waiting_connect_) { | |
| 698 if (!is_blocked_on_write_) { | |
| 699 if (!ProcessOutgoingMessages()) | |
| 700 return false; | |
| 701 } | |
| 702 } | |
| 703 | |
| 704 return true; | |
| 705 } | |
| 706 | |
| 707 int Channel::ChannelImpl::GetClientFileDescriptor() const { | |
| 708 return client_pipe_; | |
| 709 } | |
| 710 | |
| 711 // Called by libevent when we can read from th pipe without blocking. | |
| 712 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { | |
| 713 bool send_server_hello_msg = false; | |
| 714 if (waiting_connect_ && mode_ == MODE_SERVER) { | |
| 715 // In the case of a socketpair() the server starts listening on its end | |
| 716 // of the pipe in Connect(). | |
| 717 DCHECK(uses_fifo_); | |
| 718 | |
| 719 if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) { | |
| 720 Close(); | |
| 721 } | |
| 722 | |
| 723 // No need to watch the listening socket any longer since only one client | |
| 724 // can connect. So unregister with libevent. | |
| 725 server_listen_connection_watcher_.StopWatchingFileDescriptor(); | |
| 726 | |
| 727 // Start watching our end of the socket. | |
| 728 MessageLoopForIO::current()->WatchFileDescriptor( | |
| 729 pipe_, | |
| 730 true, | |
| 731 MessageLoopForIO::WATCH_READ, | |
| 732 &read_watcher_, | |
| 733 this); | |
| 734 | |
| 735 waiting_connect_ = false; | |
| 736 send_server_hello_msg = true; | |
| 737 } | |
| 738 | |
| 739 if (!waiting_connect_ && fd == pipe_) { | |
| 740 if (!ProcessIncomingMessages()) { | |
| 741 Close(); | |
| 742 listener_->OnChannelError(); | |
| 743 } | |
| 744 } | |
| 745 | |
| 746 // If we're a server and handshaking, then we want to make sure that we | |
| 747 // only send our handshake message after we've processed the client's. | |
| 748 // This gives us a chance to kill the client if the incoming handshake | |
| 749 // is invalid. | |
| 750 if (send_server_hello_msg) { | |
| 751 // This should be our first write so there's no chance we can block here... | |
| 752 DCHECK(is_blocked_on_write_ == false); | |
| 753 ProcessOutgoingMessages(); | |
| 754 } | |
| 755 } | |
| 756 | |
| 757 // Called by libevent when we can write to the pipe without blocking. | |
| 758 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { | |
| 759 if (!ProcessOutgoingMessages()) { | |
| 760 Close(); | |
| 761 listener_->OnChannelError(); | |
| 762 } | |
| 763 } | |
| 764 | |
| 765 void Channel::ChannelImpl::Close() { | |
| 766 // Close can be called multiple time, so we need to make sure we're | |
| 767 // idempotent. | |
| 768 | |
| 769 // Unregister libevent for the listening socket and close it. | |
| 770 server_listen_connection_watcher_.StopWatchingFileDescriptor(); | |
| 771 | |
| 772 if (server_listen_pipe_ != -1) { | |
| 773 HANDLE_EINTR(close(server_listen_pipe_)); | |
| 774 server_listen_pipe_ = -1; | |
| 775 } | |
| 776 | |
| 777 // Unregister libevent for the FIFO and close it. | |
| 778 read_watcher_.StopWatchingFileDescriptor(); | |
| 779 write_watcher_.StopWatchingFileDescriptor(); | |
| 780 if (pipe_ != -1) { | |
| 781 HANDLE_EINTR(close(pipe_)); | |
| 782 pipe_ = -1; | |
| 783 } | |
| 784 if (client_pipe_ != -1) { | |
| 785 Singleton<PipeMap>()->RemoveAndClose(pipe_name_); | |
| 786 client_pipe_ = -1; | |
| 787 } | |
| 788 | |
| 789 if (uses_fifo_) { | |
| 790 // Unlink the FIFO | |
| 791 unlink(pipe_name_.c_str()); | |
| 792 } | |
| 793 | |
| 794 while (!output_queue_.empty()) { | |
| 795 Message* m = output_queue_.front(); | |
| 796 output_queue_.pop(); | |
| 797 delete m; | |
| 798 } | |
| 799 | |
| 800 // Close any outstanding, received file descriptors | |
| 801 for (std::vector<int>::iterator | |
| 802 i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) { | |
| 803 HANDLE_EINTR(close(*i)); | |
| 804 } | |
| 805 input_overflow_fds_.clear(); | |
| 806 } | |
| 807 | |
| 808 //------------------------------------------------------------------------------ | |
| 809 // Channel's methods simply call through to ChannelImpl. | |
| 810 Channel::Channel(const std::string& channel_id, Mode mode, | |
| 811 Listener* listener) | |
| 812 : channel_impl_(new ChannelImpl(channel_id, mode, listener)) { | |
| 813 } | |
| 814 | |
| 815 Channel::~Channel() { | |
| 816 delete channel_impl_; | |
| 817 } | |
| 818 | |
| 819 bool Channel::Connect() { | |
| 820 return channel_impl_->Connect(); | |
| 821 } | |
| 822 | |
| 823 void Channel::Close() { | |
| 824 channel_impl_->Close(); | |
| 825 } | |
| 826 | |
| 827 void Channel::set_listener(Listener* listener) { | |
| 828 channel_impl_->set_listener(listener); | |
| 829 } | |
| 830 | |
| 831 bool Channel::Send(Message* message) { | |
| 832 return channel_impl_->Send(message); | |
| 833 } | |
| 834 | |
| 835 int Channel::GetClientFileDescriptor() const { | |
| 836 return channel_impl_->GetClientFileDescriptor(); | |
| 837 } | |
| 838 | |
| 839 } // namespace IPC | |
| OLD | NEW |