blob: 522a6bc9c4bd21d5020853b6b4e5d6f948cfa3f9 [file] [log] [blame]
[email protected]d4651ff2008-12-02 16:51:581// 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
[email protected]82e5ee82009-04-03 02:29:455#include "chrome/common/ipc_channel_posix.h"
[email protected]d4651ff2008-12-02 16:51:586
[email protected]c3110742008-12-11 00:36:477#include <errno.h>
[email protected]fa95fc92008-12-08 18:10:148#include <fcntl.h>
[email protected]e45e6c02008-12-15 22:02:179#include <stddef.h>
[email protected]fa95fc92008-12-08 18:10:1410#include <sys/types.h>
11#include <sys/socket.h>
12#include <sys/stat.h>
[email protected]e45e6c02008-12-15 22:02:1713#include <sys/un.h>
[email protected]e45e6c02008-12-15 22:02:1714
[email protected]e8fce882009-01-20 22:02:5815#include <string>
16#include <map>
17
[email protected]df3c1ca12008-12-19 21:37:0118#include "base/command_line.h"
[email protected]157c61b2009-05-01 21:37:3119#include "base/eintr_wrapper.h"
[email protected]e8fce882009-01-20 22:02:5820#include "base/lock.h"
[email protected]fa95fc92008-12-08 18:10:1421#include "base/logging.h"
22#include "base/process_util.h"
23#include "base/scoped_ptr.h"
24#include "base/string_util.h"
[email protected]e8fce882009-01-20 22:02:5825#include "base/singleton.h"
[email protected]e6f02ab2009-04-10 22:29:2926#include "base/stats_counters.h"
[email protected]82e5ee82009-04-03 02:29:4527#include "chrome/common/chrome_counters.h"
28#include "chrome/common/chrome_switches.h"
29#include "chrome/common/file_descriptor_set_posix.h"
30#include "chrome/common/ipc_logging.h"
31#include "chrome/common/ipc_message_utils.h"
[email protected]d4651ff2008-12-02 16:51:5832
33namespace IPC {
34
[email protected]fa95fc92008-12-08 18:10:1435//------------------------------------------------------------------------------
[email protected]fa95fc92008-12-08 18:10:1436namespace {
37
[email protected]e8fce882009-01-20 22:02:5838// When running as a browser, we install the client socket in a specific file
39// descriptor number (@kClientChannelFd). However, we also have to support the
40// case where we are running unittests in the same process.
41//
42// We do not support forking without execing.
43//
44// Case 1: normal running
45// The IPC server object will install a mapping in PipeMap from the
46// name which it was given to the client pipe. When forking the client, the
47// GetClientFileDescriptorMapping will ensure that the socket is installed in
48// the magic slot (@kClientChannelFd). The client will search for the
49// mapping, but it won't find any since we are in a new process. Thus the
50// magic fd number is returned. Once the client connects, the server will
51// close it's copy of the client socket and remove the mapping.
52//
53// Case 2: unittests - client and server in the same process
54// The IPC server will install a mapping as before. The client will search
55// for a mapping and find out. It duplicates the file descriptor and
56// connects. Once the client connects, the server will close the original
57// copy of the client socket and remove the mapping. Thus, when the client
58// object closes, it will close the only remaining copy of the client socket
59// in the fd table and the server will see EOF on its side.
60//
61// TODO(port): a client process cannot connect to multiple IPC channels with
62// this scheme.
63
64class PipeMap {
65 public:
66 // Lookup a given channel id. Return -1 if not found.
67 int Lookup(const std::string& channel_id) {
68 AutoLock locked(lock_);
69
70 ChannelToFDMap::const_iterator i = map_.find(channel_id);
71 if (i == map_.end())
72 return -1;
73 return i->second;
74 }
75
76 // Remove the mapping for the given channel id. No error is signaled if the
77 // channel_id doesn't exist
78 void Remove(const std::string& channel_id) {
79 AutoLock locked(lock_);
80
81 ChannelToFDMap::iterator i = map_.find(channel_id);
82 if (i != map_.end())
83 map_.erase(i);
84 }
85
86 // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
87 // mapping if one already exists for the given channel_id
88 void Insert(const std::string& channel_id, int fd) {
89 AutoLock locked(lock_);
90 DCHECK(fd != -1);
91
92 ChannelToFDMap::const_iterator i = map_.find(channel_id);
93 CHECK(i == map_.end()) << "Creating second IPC server for '"
94 << channel_id
95 << "' while first still exists";
96 map_[channel_id] = fd;
97 }
98
99 private:
100 Lock lock_;
101 typedef std::map<std::string, int> ChannelToFDMap;
102 ChannelToFDMap map_;
103};
104
105// This is the file descriptor number that a client process expects to find its
106// IPC socket.
107static const int kClientChannelFd = 3;
108
[email protected]df3c1ca12008-12-19 21:37:01109// Used to map a channel name to the equivalent FD # in the client process.
110int ChannelNameToClientFD(const std::string& channel_id) {
[email protected]e8fce882009-01-20 22:02:58111 // See the large block comment above PipeMap for the reasoning here.
112 const int fd = Singleton<PipeMap>()->Lookup(channel_id);
113 if (fd != -1)
114 return dup(fd);
115
116 // If we don't find an entry, we assume that the correct value has been
117 // inserted in the magic slot.
118 return kClientChannelFd;
[email protected]df3c1ca12008-12-19 21:37:01119}
120
121//------------------------------------------------------------------------------
[email protected]02d66512009-03-17 01:48:35122sockaddr_un sizecheck;
123const size_t kMaxPipeNameLength = sizeof(sizecheck.sun_path);
[email protected]fa95fc92008-12-08 18:10:14124
125// Creates a Fifo with the specified name ready to listen on.
126bool CreateServerFifo(const std::string &pipe_name, int* server_listen_fd) {
127 DCHECK(server_listen_fd);
[email protected]02d66512009-03-17 01:48:35128 DCHECK_GT(pipe_name.length(), 0u);
129 DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
[email protected]fa95fc92008-12-08 18:10:14130
[email protected]02d66512009-03-17 01:48:35131 if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
[email protected]fa95fc92008-12-08 18:10:14132 return false;
133 }
134
135 // Create socket.
136 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
137 if (fd < 0) {
138 return false;
139 }
140
141 // Make socket non-blocking
142 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
[email protected]157c61b2009-05-01 21:37:31143 HANDLE_EINTR(close(fd));
[email protected]fa95fc92008-12-08 18:10:14144 return false;
145 }
146
147 // Delete any old FS instances.
148 unlink(pipe_name.c_str());
149
150 // Create unix_addr structure
151 struct sockaddr_un unix_addr;
152 memset(&unix_addr, 0, sizeof(unix_addr));
153 unix_addr.sun_family = AF_UNIX;
[email protected]02d66512009-03-17 01:48:35154 snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str());
[email protected]fa95fc92008-12-08 18:10:14155 size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
156 strlen(unix_addr.sun_path) + 1;
157
158 // Bind the socket.
159 if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
160 unix_addr_len) != 0) {
[email protected]157c61b2009-05-01 21:37:31161 HANDLE_EINTR(close(fd));
[email protected]fa95fc92008-12-08 18:10:14162 return false;
163 }
164
165 // Start listening on the socket.
166 const int listen_queue_length = 1;
167 if (listen(fd, listen_queue_length) != 0) {
[email protected]157c61b2009-05-01 21:37:31168 HANDLE_EINTR(close(fd));
[email protected]fa95fc92008-12-08 18:10:14169 return false;
170 }
171
172 *server_listen_fd = fd;
173 return true;
174}
175
176// Accept a connection on a fifo.
177bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) {
178 DCHECK(server_socket);
179
[email protected]157c61b2009-05-01 21:37:31180 int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
[email protected]fa95fc92008-12-08 18:10:14181 if (accept_fd < 0)
182 return false;
[email protected]3af21262008-12-16 21:49:34183 if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
[email protected]157c61b2009-05-01 21:37:31184 HANDLE_EINTR(close(accept_fd));
[email protected]3af21262008-12-16 21:49:34185 return false;
186 }
[email protected]fa95fc92008-12-08 18:10:14187
188 *server_socket = accept_fd;
189 return true;
190}
191
192bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) {
193 DCHECK(client_socket);
[email protected]02d66512009-03-17 01:48:35194 DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
[email protected]fa95fc92008-12-08 18:10:14195
196 // Create socket.
197 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
198 if (fd < 0) {
199 LOG(ERROR) << "fd is invalid";
200 return false;
201 }
202
203 // Make socket non-blocking
204 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
[email protected]02d66512009-03-17 01:48:35205 LOG(ERROR) << "fcntl failed";
[email protected]157c61b2009-05-01 21:37:31206 HANDLE_EINTR(close(fd));
[email protected]fa95fc92008-12-08 18:10:14207 return false;
208 }
209
210 // Create server side of socket.
211 struct sockaddr_un server_unix_addr;
212 memset(&server_unix_addr, 0, sizeof(server_unix_addr));
213 server_unix_addr.sun_family = AF_UNIX;
[email protected]02d66512009-03-17 01:48:35214 snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s",
[email protected]fa95fc92008-12-08 18:10:14215 pipe_name.c_str());
216 size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
217 strlen(server_unix_addr.sun_path) + 1;
218
[email protected]157c61b2009-05-01 21:37:31219 if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
220 server_unix_addr_len)) != 0) {
221 HANDLE_EINTR(close(fd));
[email protected]fa95fc92008-12-08 18:10:14222 return false;
223 }
224
225 *client_socket = fd;
226 return true;
227}
228
229} // namespace
[email protected]d4651ff2008-12-02 16:51:58230//------------------------------------------------------------------------------
231
[email protected]514411fc2008-12-10 22:28:11232Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
233 Listener* listener)
[email protected]fa95fc92008-12-08 18:10:14234 : mode_(mode),
[email protected]e45e6c02008-12-15 22:02:17235 is_blocked_on_write_(false),
236 message_send_bytes_written_(0),
[email protected]bb975362009-01-21 01:00:22237 uses_fifo_(CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]97c42bcf2009-02-27 07:21:58238 switches::kIPCUseFIFO)),
[email protected]e45e6c02008-12-15 22:02:17239 server_listen_pipe_(-1),
240 pipe_(-1),
[email protected]df3c1ca12008-12-19 21:37:01241 client_pipe_(-1),
[email protected]e45e6c02008-12-15 22:02:17242 listener_(listener),
243 waiting_connect_(true),
244 processing_incoming_(false),
245 factory_(this) {
[email protected]fa95fc92008-12-08 18:10:14246 if (!CreatePipe(channel_id, mode)) {
247 // The pipe may have been closed already.
248 LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
249 "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
250 " mode error(" << strerror(errno) << ").";
251 }
[email protected]d4651ff2008-12-02 16:51:58252}
253
[email protected]514411fc2008-12-10 22:28:11254const std::wstring Channel::ChannelImpl::PipeName(
255 const std::wstring& channel_id) const {
[email protected]fa95fc92008-12-08 18:10:14256 // TODO(playmobil): This should live in the Chrome user data directory.
257 // TODO(playmobil): Cleanup any stale fifos.
[email protected]e8fce882009-01-20 22:02:58258 return L"/var/tmp/chrome_" + channel_id;
[email protected]d4651ff2008-12-02 16:51:58259}
260
[email protected]514411fc2008-12-10 22:28:11261bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
262 Mode mode) {
[email protected]fa95fc92008-12-08 18:10:14263 DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
[email protected]e8fce882009-01-20 22:02:58264 pipe_name_ = WideToUTF8(PipeName(channel_id));
[email protected]fa95fc92008-12-08 18:10:14265
[email protected]df3c1ca12008-12-19 21:37:01266 if (uses_fifo_) {
267 // TODO(playmobil): Should we just change pipe_name to be a normal string
268 // everywhere?
[email protected]fa95fc92008-12-08 18:10:14269
[email protected]df3c1ca12008-12-19 21:37:01270 if (mode == MODE_SERVER) {
271 if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) {
272 return false;
273 }
274 } else {
275 if (!ClientConnectToFifo(pipe_name_, &pipe_)) {
276 return false;
277 }
278 waiting_connect_ = false;
[email protected]fa95fc92008-12-08 18:10:14279 }
280 } else {
[email protected]df3c1ca12008-12-19 21:37:01281 // socketpair()
282 if (mode == MODE_SERVER) {
283 int pipe_fds[2];
284 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
285 return false;
286 }
287 // Set both ends to be non-blocking.
288 if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
289 fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
[email protected]157c61b2009-05-01 21:37:31290 HANDLE_EINTR(close(pipe_fds[0]));
291 HANDLE_EINTR(close(pipe_fds[1]));
[email protected]df3c1ca12008-12-19 21:37:01292 return false;
293 }
294 pipe_ = pipe_fds[0];
295 client_pipe_ = pipe_fds[1];
[email protected]e8fce882009-01-20 22:02:58296
297 Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
[email protected]df3c1ca12008-12-19 21:37:01298 } else {
299 pipe_ = ChannelNameToClientFD(pipe_name_);
300 DCHECK(pipe_ > 0);
301 waiting_connect_ = false;
[email protected]fa95fc92008-12-08 18:10:14302 }
[email protected]fa95fc92008-12-08 18:10:14303 }
304
305 // Create the Hello message to be sent when Connect is called
306 scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
307 HELLO_MESSAGE_TYPE,
308 IPC::Message::PRIORITY_NORMAL));
309 if (!msg->WriteInt(base::GetCurrentProcId())) {
310 Close();
311 return false;
312 }
313
314 output_queue_.push(msg.release());
315 return true;
[email protected]d4651ff2008-12-02 16:51:58316}
317
[email protected]514411fc2008-12-10 22:28:11318bool Channel::ChannelImpl::Connect() {
[email protected]df3c1ca12008-12-19 21:37:01319 if (mode_ == MODE_SERVER && uses_fifo_) {
[email protected]fa95fc92008-12-08 18:10:14320 if (server_listen_pipe_ == -1) {
321 return false;
322 }
[email protected]e45e6c02008-12-15 22:02:17323 MessageLoopForIO::current()->WatchFileDescriptor(
324 server_listen_pipe_,
325 true,
326 MessageLoopForIO::WATCH_READ,
327 &server_listen_connection_watcher_,
328 this);
[email protected]fa95fc92008-12-08 18:10:14329 } else {
330 if (pipe_ == -1) {
331 return false;
332 }
[email protected]e45e6c02008-12-15 22:02:17333 MessageLoopForIO::current()->WatchFileDescriptor(
334 pipe_,
335 true,
336 MessageLoopForIO::WATCH_READ,
337 &read_watcher_,
338 this);
[email protected]fa95fc92008-12-08 18:10:14339 waiting_connect_ = false;
340 }
341
342 if (!waiting_connect_)
343 return ProcessOutgoingMessages();
344 return true;
[email protected]d4651ff2008-12-02 16:51:58345}
[email protected]fa95fc92008-12-08 18:10:14346
[email protected]514411fc2008-12-10 22:28:11347bool Channel::ChannelImpl::ProcessIncomingMessages() {
[email protected]fa95fc92008-12-08 18:10:14348 ssize_t bytes_read = 0;
349
[email protected]526776c2009-02-07 00:39:26350 struct msghdr msg = {0};
351 struct iovec iov = {input_buf_, Channel::kReadBufferSize};
352
353 msg.msg_iov = &iov;
354 msg.msg_iovlen = 1;
355 msg.msg_control = input_cmsg_buf_;
[email protected]526776c2009-02-07 00:39:26356
[email protected]fa95fc92008-12-08 18:10:14357 for (;;) {
[email protected]cef7c522009-02-10 08:15:02358 msg.msg_controllen = sizeof(input_cmsg_buf_);
359
[email protected]fa95fc92008-12-08 18:10:14360 if (bytes_read == 0) {
361 if (pipe_ == -1)
362 return false;
363
364 // Read from pipe.
[email protected]526776c2009-02-07 00:39:26365 // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
366 // is waiting on the pipe.
[email protected]157c61b2009-05-01 21:37:31367 bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
[email protected]3d1b6662009-01-29 17:03:11368
[email protected]fa95fc92008-12-08 18:10:14369 if (bytes_read < 0) {
370 if (errno == EAGAIN) {
371 return true;
372 } else {
[email protected]e8fce882009-01-20 22:02:58373 LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
[email protected]fa95fc92008-12-08 18:10:14374 return false;
375 }
376 } else if (bytes_read == 0) {
377 // The pipe has closed...
378 Close();
[email protected]e8fce882009-01-20 22:02:58379 return false;
[email protected]fa95fc92008-12-08 18:10:14380 }
381 }
382 DCHECK(bytes_read);
383
[email protected]e8fce882009-01-20 22:02:58384 if (client_pipe_ != -1) {
385 Singleton<PipeMap>()->Remove(pipe_name_);
[email protected]157c61b2009-05-01 21:37:31386 HANDLE_EINTR(close(client_pipe_));
[email protected]e8fce882009-01-20 22:02:58387 client_pipe_ = -1;
388 }
389
[email protected]526776c2009-02-07 00:39:26390 // a pointer to an array of |num_wire_fds| file descriptors from the read
[email protected]337c6bf2009-02-07 00:51:58391 const int* wire_fds = NULL;
[email protected]526776c2009-02-07 00:39:26392 unsigned num_wire_fds = 0;
393
394 // walk the list of control messages and, if we find an array of file
395 // descriptors, save a pointer to the array
[email protected]526776c2009-02-07 00:39:26396
[email protected]afb4bad2009-02-12 02:39:31397 // This next if statement is to work around an OSX issue where
398 // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
399 // Here's a test case:
400 //
401 // int main() {
402 // struct msghdr msg;
403 // msg.msg_control = &msg;
404 // msg.msg_controllen = 0;
405 // if (CMSG_FIRSTHDR(&msg))
406 // printf("Bug found!\n");
407 // }
408 if (msg.msg_controllen > 0) {
409 // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
410 // and will return a pointer into nowhere.
411 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
412 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
413 if (cmsg->cmsg_level == SOL_SOCKET &&
414 cmsg->cmsg_type == SCM_RIGHTS) {
415 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
416 DCHECK(payload_len % sizeof(int) == 0);
417 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
418 num_wire_fds = payload_len / 4;
419
420 if (msg.msg_flags & MSG_CTRUNC) {
421 LOG(ERROR) << "SCM_RIGHTS message was truncated"
422 << " cmsg_len:" << cmsg->cmsg_len
423 << " fd:" << pipe_;
424 for (unsigned i = 0; i < num_wire_fds; ++i)
[email protected]157c61b2009-05-01 21:37:31425 HANDLE_EINTR(close(wire_fds[i]));
[email protected]afb4bad2009-02-12 02:39:31426 return false;
427 }
428 break;
[email protected]526776c2009-02-07 00:39:26429 }
[email protected]526776c2009-02-07 00:39:26430 }
431 }
432
[email protected]fa95fc92008-12-08 18:10:14433 // Process messages from input buffer.
434 const char *p;
435 const char *end;
436 if (input_overflow_buf_.empty()) {
437 p = input_buf_;
438 end = p + bytes_read;
439 } else {
440 if (input_overflow_buf_.size() >
441 static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
442 input_overflow_buf_.clear();
443 LOG(ERROR) << "IPC message is too big";
444 return false;
445 }
446 input_overflow_buf_.append(input_buf_, bytes_read);
447 p = input_overflow_buf_.data();
448 end = p + input_overflow_buf_.size();
449 }
450
[email protected]526776c2009-02-07 00:39:26451 // A pointer to an array of |num_fds| file descriptors which includes any
452 // fds that have spilled over from a previous read.
453 const int* fds;
454 unsigned num_fds;
455 unsigned fds_i = 0; // the index of the first unused descriptor
456
457 if (input_overflow_fds_.empty()) {
458 fds = wire_fds;
459 num_fds = num_wire_fds;
460 } else {
461 const size_t prev_size = input_overflow_fds_.size();
462 input_overflow_fds_.resize(prev_size + num_wire_fds);
463 memcpy(&input_overflow_fds_[prev_size], wire_fds,
464 num_wire_fds * sizeof(int));
465 fds = &input_overflow_fds_[0];
466 num_fds = input_overflow_fds_.size();
467 }
468
[email protected]fa95fc92008-12-08 18:10:14469 while (p < end) {
470 const char* message_tail = Message::FindNext(p, end);
471 if (message_tail) {
472 int len = static_cast<int>(message_tail - p);
[email protected]7135bb042009-02-12 04:05:28473 Message m(p, len);
[email protected]526776c2009-02-07 00:39:26474 if (m.header()->num_fds) {
475 // the message has file descriptors
[email protected]7135bb042009-02-12 04:05:28476 const char* error = NULL;
[email protected]526776c2009-02-07 00:39:26477 if (m.header()->num_fds > num_fds - fds_i) {
478 // the message has been completely received, but we didn't get
479 // enough file descriptors.
[email protected]7135bb042009-02-12 04:05:28480 error = "Message needs unreceived descriptors";
481 }
482
483 if (m.header()->num_fds >
[email protected]d0c0b1d2009-02-12 18:32:45484 FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
[email protected]7135bb042009-02-12 04:05:28485 // There are too many descriptors in this message
486 error = "Message requires an excessive number of descriptors";
487 }
488
489 if (error) {
490 LOG(WARNING) << error
[email protected]526776c2009-02-07 00:39:26491 << " channel:" << this
492 << " message-type:" << m.type()
493 << " header()->num_fds:" << m.header()->num_fds
494 << " num_fds:" << num_fds
495 << " fds_i:" << fds_i;
496 // close the existing file descriptors so that we don't leak them
497 for (unsigned i = fds_i; i < num_fds; ++i)
[email protected]157c61b2009-05-01 21:37:31498 HANDLE_EINTR(close(fds[i]));
[email protected]526776c2009-02-07 00:39:26499 input_overflow_fds_.clear();
[email protected]7135bb042009-02-12 04:05:28500 // abort the connection
[email protected]526776c2009-02-07 00:39:26501 return false;
502 }
503
[email protected]d0c0b1d2009-02-12 18:32:45504 m.file_descriptor_set()->SetDescriptors(
505 &fds[fds_i], m.header()->num_fds);
[email protected]526776c2009-02-07 00:39:26506 fds_i += m.header()->num_fds;
507 }
[email protected]fa95fc92008-12-08 18:10:14508#ifdef IPC_MESSAGE_DEBUG_EXTRA
509 DLOG(INFO) << "received message on channel @" << this <<
510 " with type " << m.type();
511#endif
512 if (m.routing_id() == MSG_ROUTING_NONE &&
513 m.type() == HELLO_MESSAGE_TYPE) {
514 // The Hello message contains only the process id.
515 listener_->OnChannelConnected(MessageIterator(m).NextInt());
516 } else {
517 listener_->OnMessageReceived(m);
518 }
519 p = message_tail;
520 } else {
521 // Last message is partial.
522 break;
523 }
524 }
525 input_overflow_buf_.assign(p, end - p);
[email protected]526776c2009-02-07 00:39:26526 input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
[email protected]fa95fc92008-12-08 18:10:14527
[email protected]afb4bad2009-02-12 02:39:31528 // When the input data buffer is empty, the overflow fds should be too. If
529 // this is not the case, we probably have a rogue renderer which is trying
530 // to fill our descriptor table.
531 if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) {
532 // We close these descriptors in Close()
533 return false;
534 }
535
[email protected]fa95fc92008-12-08 18:10:14536 bytes_read = 0; // Get more data.
537 }
538
539 return true;
540}
541
[email protected]514411fc2008-12-10 22:28:11542bool Channel::ChannelImpl::ProcessOutgoingMessages() {
[email protected]fa95fc92008-12-08 18:10:14543 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
544 // no connection?
[email protected]e45e6c02008-12-15 22:02:17545 is_blocked_on_write_ = false;
[email protected]fa95fc92008-12-08 18:10:14546
547 if (output_queue_.empty())
548 return true;
549
550 if (pipe_ == -1)
551 return false;
552
[email protected]fa95fc92008-12-08 18:10:14553 // Write out all the messages we can till the write blocks or there are no
554 // more outgoing messages.
555 while (!output_queue_.empty()) {
556 Message* msg = output_queue_.front();
557
558 size_t amt_to_write = msg->size() - message_send_bytes_written_;
[email protected]3d1b6662009-01-29 17:03:11559 DCHECK(amt_to_write != 0);
[email protected]fa95fc92008-12-08 18:10:14560 const char *out_bytes = reinterpret_cast<const char*>(msg->data()) +
561 message_send_bytes_written_;
[email protected]526776c2009-02-07 00:39:26562
[email protected]157c61b2009-05-01 21:37:31563 struct msghdr msgh = {0};
564 struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
565 msgh.msg_iov = &iov;
566 msgh.msg_iovlen = 1;
567 char buf[CMSG_SPACE(
568 sizeof(int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]))];
[email protected]526776c2009-02-07 00:39:26569
[email protected]157c61b2009-05-01 21:37:31570 if (message_send_bytes_written_ == 0 &&
571 !msg->file_descriptor_set()->empty()) {
572 // This is the first chunk of a message which has descriptors to send
573 struct cmsghdr *cmsg;
574 const unsigned num_fds = msg->file_descriptor_set()->size();
[email protected]526776c2009-02-07 00:39:26575
[email protected]157c61b2009-05-01 21:37:31576 DCHECK_LE(num_fds, FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE);
[email protected]526776c2009-02-07 00:39:26577
[email protected]157c61b2009-05-01 21:37:31578 msgh.msg_control = buf;
579 msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
580 cmsg = CMSG_FIRSTHDR(&msgh);
581 cmsg->cmsg_level = SOL_SOCKET;
582 cmsg->cmsg_type = SCM_RIGHTS;
583 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
584 msg->file_descriptor_set()->GetDescriptors(
585 reinterpret_cast<int*>(CMSG_DATA(cmsg)));
586 msgh.msg_controllen = cmsg->cmsg_len;
[email protected]526776c2009-02-07 00:39:26587
[email protected]157c61b2009-05-01 21:37:31588 msg->header()->num_fds = num_fds;
589 }
590
591 ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
592 if (bytes_written > 0)
593 msg->file_descriptor_set()->CommitAll();
[email protected]fa95fc92008-12-08 18:10:14594
[email protected]3d1b6662009-01-29 17:03:11595 if (bytes_written < 0 && errno != EAGAIN) {
[email protected]fa95fc92008-12-08 18:10:14596 LOG(ERROR) << "pipe error: " << strerror(errno);
597 return false;
598 }
599
600 if (static_cast<size_t>(bytes_written) != amt_to_write) {
[email protected]3d1b6662009-01-29 17:03:11601 if (bytes_written > 0) {
602 // If write() fails with EAGAIN then bytes_written will be -1.
603 message_send_bytes_written_ += bytes_written;
604 }
[email protected]fa95fc92008-12-08 18:10:14605
606 // Tell libevent to call us back once things are unblocked.
[email protected]e45e6c02008-12-15 22:02:17607 is_blocked_on_write_ = true;
608 MessageLoopForIO::current()->WatchFileDescriptor(
609 pipe_,
610 false, // One shot
611 MessageLoopForIO::WATCH_WRITE,
612 &write_watcher_,
613 this);
[email protected]3d1b6662009-01-29 17:03:11614 return true;
[email protected]fa95fc92008-12-08 18:10:14615 } else {
616 message_send_bytes_written_ = 0;
617
618 // Message sent OK!
619#ifdef IPC_MESSAGE_DEBUG_EXTRA
620 DLOG(INFO) << "sent message @" << msg << " on channel @" << this <<
621 " with type " << msg->type();
622#endif
623 output_queue_.pop();
624 delete msg;
625 }
626 }
627 return true;
628}
629
[email protected]514411fc2008-12-10 22:28:11630bool Channel::ChannelImpl::Send(Message* message) {
[email protected]82e5ee82009-04-03 02:29:45631 chrome::Counters::ipc_send_counter().Increment();
[email protected]fa95fc92008-12-08 18:10:14632#ifdef IPC_MESSAGE_DEBUG_EXTRA
633 DLOG(INFO) << "sending message @" << message << " on channel @" << this
634 << " with type " << message->type()
635 << " (" << output_queue_.size() << " in queue)";
636#endif
637
[email protected]4c2c1db2009-03-20 20:56:55638#ifdef IPC_MESSAGE_LOG_ENABLED
639 Logging::current()->OnSendMessage(message, L"");
640#endif
[email protected]fa95fc92008-12-08 18:10:14641
642 output_queue_.push(message);
643 if (!waiting_connect_) {
[email protected]e45e6c02008-12-15 22:02:17644 if (!is_blocked_on_write_) {
[email protected]fa95fc92008-12-08 18:10:14645 if (!ProcessOutgoingMessages())
646 return false;
647 }
648 }
649
650 return true;
651}
652
[email protected]df3c1ca12008-12-19 21:37:01653void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd,
[email protected]157e5d22009-04-23 18:43:35654 int *dest_fd) const {
[email protected]df3c1ca12008-12-19 21:37:01655 DCHECK(mode_ == MODE_SERVER);
656 *src_fd = client_pipe_;
[email protected]e8fce882009-01-20 22:02:58657 *dest_fd = kClientChannelFd;
[email protected]df3c1ca12008-12-19 21:37:01658}
659
660void Channel::ChannelImpl::OnClientConnected() {
[email protected]e8fce882009-01-20 22:02:58661 // WARNING: this isn't actually called when a client connects.
[email protected]df3c1ca12008-12-19 21:37:01662 DCHECK(mode_ == MODE_SERVER);
[email protected]df3c1ca12008-12-19 21:37:01663}
664
[email protected]fa95fc92008-12-08 18:10:14665// Called by libevent when we can read from th pipe without blocking.
[email protected]e45e6c02008-12-15 22:02:17666void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
[email protected]fa95fc92008-12-08 18:10:14667 bool send_server_hello_msg = false;
668 if (waiting_connect_ && mode_ == MODE_SERVER) {
[email protected]df3c1ca12008-12-19 21:37:01669 // In the case of a socketpair() the server starts listening on its end
670 // of the pipe in Connect().
671 DCHECK(uses_fifo_);
672
[email protected]fa95fc92008-12-08 18:10:14673 if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) {
674 Close();
675 }
676
677 // No need to watch the listening socket any longer since only one client
678 // can connect. So unregister with libevent.
[email protected]e45e6c02008-12-15 22:02:17679 server_listen_connection_watcher_.StopWatchingFileDescriptor();
[email protected]fa95fc92008-12-08 18:10:14680
681 // Start watching our end of the socket.
[email protected]e45e6c02008-12-15 22:02:17682 MessageLoopForIO::current()->WatchFileDescriptor(
683 pipe_,
684 true,
685 MessageLoopForIO::WATCH_READ,
686 &read_watcher_,
687 this);
688
[email protected]fa95fc92008-12-08 18:10:14689 waiting_connect_ = false;
690 send_server_hello_msg = true;
691 }
692
693 if (!waiting_connect_ && fd == pipe_) {
694 if (!ProcessIncomingMessages()) {
695 Close();
696 listener_->OnChannelError();
697 }
698 }
699
700 // If we're a server and handshaking, then we want to make sure that we
701 // only send our handshake message after we've processed the client's.
702 // This gives us a chance to kill the client if the incoming handshake
703 // is invalid.
704 if (send_server_hello_msg) {
[email protected]3d1b6662009-01-29 17:03:11705 // This should be our first write so there's no chance we can block here...
[email protected]e45e6c02008-12-15 22:02:17706 DCHECK(is_blocked_on_write_ == false);
[email protected]fa95fc92008-12-08 18:10:14707 ProcessOutgoingMessages();
708 }
709}
710
711// Called by libevent when we can write to the pipe without blocking.
[email protected]e45e6c02008-12-15 22:02:17712void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
[email protected]fa95fc92008-12-08 18:10:14713 if (!ProcessOutgoingMessages()) {
714 Close();
715 listener_->OnChannelError();
716 }
717}
718
[email protected]514411fc2008-12-10 22:28:11719void Channel::ChannelImpl::Close() {
[email protected]fa95fc92008-12-08 18:10:14720 // Close can be called multiple time, so we need to make sure we're
721 // idempotent.
722
723 // Unregister libevent for the listening socket and close it.
[email protected]e45e6c02008-12-15 22:02:17724 server_listen_connection_watcher_.StopWatchingFileDescriptor();
[email protected]fa95fc92008-12-08 18:10:14725
726 if (server_listen_pipe_ != -1) {
[email protected]157c61b2009-05-01 21:37:31727 HANDLE_EINTR(close(server_listen_pipe_));
[email protected]fa95fc92008-12-08 18:10:14728 server_listen_pipe_ = -1;
729 }
730
731 // Unregister libevent for the FIFO and close it.
[email protected]e45e6c02008-12-15 22:02:17732 read_watcher_.StopWatchingFileDescriptor();
733 write_watcher_.StopWatchingFileDescriptor();
[email protected]fa95fc92008-12-08 18:10:14734 if (pipe_ != -1) {
[email protected]157c61b2009-05-01 21:37:31735 HANDLE_EINTR(close(pipe_));
[email protected]fa95fc92008-12-08 18:10:14736 pipe_ = -1;
737 }
[email protected]df3c1ca12008-12-19 21:37:01738 if (client_pipe_ != -1) {
[email protected]e8fce882009-01-20 22:02:58739 Singleton<PipeMap>()->Remove(pipe_name_);
[email protected]157c61b2009-05-01 21:37:31740 HANDLE_EINTR(close(client_pipe_));
[email protected]df3c1ca12008-12-19 21:37:01741 client_pipe_ = -1;
742 }
[email protected]fa95fc92008-12-08 18:10:14743
[email protected]fa95fc92008-12-08 18:10:14744 // Unlink the FIFO
745 unlink(pipe_name_.c_str());
746
747 while (!output_queue_.empty()) {
748 Message* m = output_queue_.front();
749 output_queue_.pop();
750 delete m;
751 }
[email protected]526776c2009-02-07 00:39:26752
753 // Close any outstanding, received file descriptors
754 for (std::vector<int>::iterator
755 i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
[email protected]157c61b2009-05-01 21:37:31756 HANDLE_EINTR(close(*i));
[email protected]526776c2009-02-07 00:39:26757 }
758 input_overflow_fds_.clear();
[email protected]fa95fc92008-12-08 18:10:14759}
760
[email protected]514411fc2008-12-10 22:28:11761//------------------------------------------------------------------------------
762// Channel's methods simply call through to ChannelImpl.
763Channel::Channel(const std::wstring& channel_id, Mode mode,
764 Listener* listener)
765 : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
766}
767
768Channel::~Channel() {
769 delete channel_impl_;
770}
771
772bool Channel::Connect() {
773 return channel_impl_->Connect();
774}
775
776void Channel::Close() {
777 channel_impl_->Close();
778}
779
780void Channel::set_listener(Listener* listener) {
781 channel_impl_->set_listener(listener);
782}
783
784bool Channel::Send(Message* message) {
785 return channel_impl_->Send(message);
786}
787
[email protected]157e5d22009-04-23 18:43:35788void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
[email protected]df3c1ca12008-12-19 21:37:01789 return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
790}
791
792void Channel::OnClientConnected() {
793 return channel_impl_->OnClientConnected();
794}
795
796
[email protected]d4651ff2008-12-02 16:51:58797} // namespace IPC