OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/common/ipc_channel_posix.h" | 5 #include "chrome/common/ipc_channel_posix.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <stddef.h> | |
10 #include <sys/types.h> | 9 #include <sys/types.h> |
11 #include <sys/socket.h> | 10 #include <sys/socket.h> |
12 #include <sys/stat.h> | 11 #include <sys/stat.h> |
13 #if defined(OS_LINUX) | 12 #include <stddef.h> |
14 #include <linux/un.h> | |
15 #elif defined(OS_MACOSX) | |
16 #include <sys/un.h> | |
17 #endif | |
18 | |
19 | 13 |
20 #include "base/logging.h" | 14 #include "base/logging.h" |
21 #include "base/process_util.h" | 15 #include "base/process_util.h" |
22 #include "base/scoped_ptr.h" | 16 #include "base/scoped_ptr.h" |
23 #include "base/string_util.h" | 17 #include "base/string_util.h" |
24 #include "chrome/common/chrome_counters.h" | 18 #include "chrome/common/chrome_counters.h" |
25 #include "chrome/common/ipc_message_utils.h" | 19 #include "chrome/common/ipc_message_utils.h" |
26 | 20 |
| 21 #if defined(OS_LINUX) |
| 22 #include <linux/un.h> |
| 23 #elif defined(OS_MACOSX) |
| 24 #include <sys/un.h> |
| 25 #endif |
| 26 |
27 namespace IPC { | 27 namespace IPC { |
28 | 28 |
29 //------------------------------------------------------------------------------ | 29 //------------------------------------------------------------------------------ |
30 // TODO(playmobil): Only use FIFOs for debugging, for real work, use a | 30 // TODO(playmobil): Only use FIFOs for debugging, for real work, use a |
31 // socketpair. | 31 // socketpair. |
32 namespace { | 32 namespace { |
33 | 33 |
34 // The -1 is to take the NULL terminator into account. | 34 // The -1 is to take the NULL terminator into account. |
35 #if defined(OS_LINUX) | 35 #if defined(OS_LINUX) |
36 const size_t kMaxPipeNameLength = UNIX_PATH_MAX - 1; | 36 const size_t kMaxPipeNameLength = UNIX_PATH_MAX - 1; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 *client_socket = fd; | 143 *client_socket = fd; |
144 return true; | 144 return true; |
145 } | 145 } |
146 | 146 |
147 } // namespace | 147 } // namespace |
148 //------------------------------------------------------------------------------ | 148 //------------------------------------------------------------------------------ |
149 | 149 |
150 Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode, | 150 Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode, |
151 Listener* listener) | 151 Listener* listener) |
152 : mode_(mode), | 152 : mode_(mode), |
153 is_blocked_on_write_(false), | 153 server_listen_connection_event_(new EventHolder()), |
| 154 read_event_(new EventHolder()), |
| 155 write_event_(new EventHolder()), |
154 message_send_bytes_written_(0), | 156 message_send_bytes_written_(0), |
155 server_listen_pipe_(-1), | 157 server_listen_pipe_(-1), |
156 pipe_(-1), | 158 pipe_(-1), |
157 listener_(listener), | 159 listener_(listener), |
158 waiting_connect_(true), | 160 waiting_connect_(true), |
159 processing_incoming_(false), | 161 processing_incoming_(false), |
160 factory_(this) { | 162 factory_(this) { |
161 if (!CreatePipe(channel_id, mode)) { | 163 if (!CreatePipe(channel_id, mode)) { |
162 // The pipe may have been closed already. | 164 // The pipe may have been closed already. |
163 LOG(WARNING) << "Unable to create pipe named \"" << channel_id << | 165 LOG(WARNING) << "Unable to create pipe named \"" << channel_id << |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 | 207 |
206 output_queue_.push(msg.release()); | 208 output_queue_.push(msg.release()); |
207 return true; | 209 return true; |
208 } | 210 } |
209 | 211 |
210 bool Channel::ChannelImpl::Connect() { | 212 bool Channel::ChannelImpl::Connect() { |
211 if (mode_ == MODE_SERVER) { | 213 if (mode_ == MODE_SERVER) { |
212 if (server_listen_pipe_ == -1) { | 214 if (server_listen_pipe_ == -1) { |
213 return false; | 215 return false; |
214 } | 216 } |
215 MessageLoopForIO::current()->WatchFileDescriptor( | 217 event *ev = &(server_listen_connection_event_->event); |
216 server_listen_pipe_, | 218 MessageLoopForIO::current()->WatchFileHandle(server_listen_pipe_, |
217 true, | 219 EV_READ | EV_PERSIST, |
218 MessageLoopForIO::WATCH_READ, | 220 ev, |
219 &server_listen_connection_watcher_, | 221 this); |
220 this); | 222 server_listen_connection_event_->is_active = true; |
221 } else { | 223 } else { |
222 if (pipe_ == -1) { | 224 if (pipe_ == -1) { |
223 return false; | 225 return false; |
224 } | 226 } |
225 MessageLoopForIO::current()->WatchFileDescriptor( | 227 MessageLoopForIO::current()->WatchFileHandle(pipe_, |
226 pipe_, | 228 EV_READ | EV_PERSIST, |
227 true, | 229 &(read_event_->event), |
228 MessageLoopForIO::WATCH_READ, | 230 this); |
229 &read_watcher_, | 231 read_event_->is_active = true; |
230 this); | |
231 waiting_connect_ = false; | 232 waiting_connect_ = false; |
232 } | 233 } |
233 | 234 |
234 if (!waiting_connect_) | 235 if (!waiting_connect_) |
235 return ProcessOutgoingMessages(); | 236 return ProcessOutgoingMessages(); |
236 return true; | 237 return true; |
237 } | 238 } |
238 | 239 |
239 bool Channel::ChannelImpl::ProcessIncomingMessages() { | 240 bool Channel::ChannelImpl::ProcessIncomingMessages() { |
240 ssize_t bytes_read = 0; | 241 ssize_t bytes_read = 0; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 | 310 |
310 bytes_read = 0; // Get more data. | 311 bytes_read = 0; // Get more data. |
311 } | 312 } |
312 | 313 |
313 return true; | 314 return true; |
314 } | 315 } |
315 | 316 |
316 bool Channel::ChannelImpl::ProcessOutgoingMessages() { | 317 bool Channel::ChannelImpl::ProcessOutgoingMessages() { |
317 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 318 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
318 // no connection? | 319 // no connection? |
319 is_blocked_on_write_ = false; | |
320 | 320 |
321 if (output_queue_.empty()) | 321 if (output_queue_.empty()) |
322 return true; | 322 return true; |
323 | 323 |
324 if (pipe_ == -1) | 324 if (pipe_ == -1) |
325 return false; | 325 return false; |
326 | 326 |
| 327 // If libevent was monitoring the socket for us (we blocked when trying to |
| 328 // write a message last time), then delete the underlying libevent structure. |
| 329 if (write_event_->is_active) { |
| 330 // TODO(playmobil): This calls event_del(), but we can probably |
| 331 // do with just calling event_add here. |
| 332 MessageLoopForIO::current()->UnwatchFileHandle(&(write_event_->event)); |
| 333 write_event_->is_active = false; |
| 334 } |
| 335 |
327 // Write out all the messages we can till the write blocks or there are no | 336 // Write out all the messages we can till the write blocks or there are no |
328 // more outgoing messages. | 337 // more outgoing messages. |
329 while (!output_queue_.empty()) { | 338 while (!output_queue_.empty()) { |
330 Message* msg = output_queue_.front(); | 339 Message* msg = output_queue_.front(); |
331 | 340 |
332 size_t amt_to_write = msg->size() - message_send_bytes_written_; | 341 size_t amt_to_write = msg->size() - message_send_bytes_written_; |
333 const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + | 342 const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + |
334 message_send_bytes_written_; | 343 message_send_bytes_written_; |
335 ssize_t bytes_written = -1; | 344 ssize_t bytes_written = -1; |
336 do { | 345 do { |
337 bytes_written = write(pipe_, out_bytes, amt_to_write); | 346 bytes_written = write(pipe_, out_bytes, amt_to_write); |
338 } while (bytes_written == -1 && errno == EINTR); | 347 } while (bytes_written == -1 && errno == EINTR); |
339 | 348 |
340 if (bytes_written < 0) { | 349 if (bytes_written < 0) { |
341 LOG(ERROR) << "pipe error: " << strerror(errno); | 350 LOG(ERROR) << "pipe error: " << strerror(errno); |
342 return false; | 351 return false; |
343 } | 352 } |
344 | 353 |
345 if (static_cast<size_t>(bytes_written) != amt_to_write) { | 354 if (static_cast<size_t>(bytes_written) != amt_to_write) { |
346 message_send_bytes_written_ += bytes_written; | 355 message_send_bytes_written_ += bytes_written; |
347 | 356 |
348 // Tell libevent to call us back once things are unblocked. | 357 // Tell libevent to call us back once things are unblocked. |
349 is_blocked_on_write_ = true; | 358 MessageLoopForIO::current()->WatchFileHandle(server_listen_pipe_, |
350 MessageLoopForIO::current()->WatchFileDescriptor( | 359 EV_WRITE, |
351 pipe_, | 360 &(write_event_->event), |
352 false, // One shot | 361 this); |
353 MessageLoopForIO::WATCH_WRITE, | 362 write_event_->is_active = true; |
354 &write_watcher_, | 363 |
355 this); | |
356 } else { | 364 } else { |
357 message_send_bytes_written_ = 0; | 365 message_send_bytes_written_ = 0; |
358 | 366 |
359 // Message sent OK! | 367 // Message sent OK! |
360 #ifdef IPC_MESSAGE_DEBUG_EXTRA | 368 #ifdef IPC_MESSAGE_DEBUG_EXTRA |
361 DLOG(INFO) << "sent message @" << msg << " on channel @" << this << | 369 DLOG(INFO) << "sent message @" << msg << " on channel @" << this << |
362 " with type " << msg->type(); | 370 " with type " << msg->type(); |
363 #endif | 371 #endif |
364 output_queue_.pop(); | 372 output_queue_.pop(); |
365 delete msg; | 373 delete msg; |
(...skipping 10 matching lines...) Expand all Loading... |
376 << " (" << output_queue_.size() << " in queue)"; | 384 << " (" << output_queue_.size() << " in queue)"; |
377 #endif | 385 #endif |
378 | 386 |
379 // TODO(playmobil): implement | 387 // TODO(playmobil): implement |
380 // #ifdef IPC_MESSAGE_LOG_ENABLED | 388 // #ifdef IPC_MESSAGE_LOG_ENABLED |
381 // Logging::current()->OnSendMessage(message, L""); | 389 // Logging::current()->OnSendMessage(message, L""); |
382 // #endif | 390 // #endif |
383 | 391 |
384 output_queue_.push(message); | 392 output_queue_.push(message); |
385 if (!waiting_connect_) { | 393 if (!waiting_connect_) { |
386 if (!is_blocked_on_write_) { | 394 if (!write_event_->is_active) { |
387 if (!ProcessOutgoingMessages()) | 395 if (!ProcessOutgoingMessages()) |
388 return false; | 396 return false; |
389 } | 397 } |
390 } | 398 } |
391 | 399 |
392 return true; | 400 return true; |
393 } | 401 } |
394 | 402 |
395 // Called by libevent when we can read from th pipe without blocking. | 403 // Called by libevent when we can read from th pipe without blocking. |
396 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { | 404 void Channel::ChannelImpl::OnFileReadReady(int fd) { |
397 bool send_server_hello_msg = false; | 405 bool send_server_hello_msg = false; |
398 if (waiting_connect_ && mode_ == MODE_SERVER) { | 406 if (waiting_connect_ && mode_ == MODE_SERVER) { |
399 if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) { | 407 if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) { |
400 Close(); | 408 Close(); |
401 } | 409 } |
402 | 410 |
403 // No need to watch the listening socket any longer since only one client | 411 // No need to watch the listening socket any longer since only one client |
404 // can connect. So unregister with libevent. | 412 // can connect. So unregister with libevent. |
405 server_listen_connection_watcher_.StopWatchingFileDescriptor(); | 413 event *ev = &(server_listen_connection_event_->event); |
| 414 MessageLoopForIO::current()->UnwatchFileHandle(ev); |
| 415 server_listen_connection_event_->is_active = false; |
406 | 416 |
407 // Start watching our end of the socket. | 417 // Start watching our end of the socket. |
408 MessageLoopForIO::current()->WatchFileDescriptor( | 418 MessageLoopForIO::current()->WatchFileHandle(pipe_, |
409 pipe_, | 419 EV_READ | EV_PERSIST, |
410 true, | 420 &(read_event_->event), |
411 MessageLoopForIO::WATCH_READ, | 421 this); |
412 &read_watcher_, | 422 read_event_->is_active = true; |
413 this); | |
414 | |
415 waiting_connect_ = false; | 423 waiting_connect_ = false; |
416 send_server_hello_msg = true; | 424 send_server_hello_msg = true; |
417 } | 425 } |
418 | 426 |
419 if (!waiting_connect_ && fd == pipe_) { | 427 if (!waiting_connect_ && fd == pipe_) { |
420 if (!ProcessIncomingMessages()) { | 428 if (!ProcessIncomingMessages()) { |
421 Close(); | 429 Close(); |
422 listener_->OnChannelError(); | 430 listener_->OnChannelError(); |
423 } | 431 } |
424 } | 432 } |
425 | 433 |
426 // If we're a server and handshaking, then we want to make sure that we | 434 // If we're a server and handshaking, then we want to make sure that we |
427 // only send our handshake message after we've processed the client's. | 435 // only send our handshake message after we've processed the client's. |
428 // This gives us a chance to kill the client if the incoming handshake | 436 // This gives us a chance to kill the client if the incoming handshake |
429 // is invalid. | 437 // is invalid. |
430 if (send_server_hello_msg) { | 438 if (send_server_hello_msg) { |
431 // This should be our first write so there' sno chance we can block here... | |
432 DCHECK(is_blocked_on_write_ == false); | |
433 ProcessOutgoingMessages(); | 439 ProcessOutgoingMessages(); |
434 } | 440 } |
435 } | 441 } |
436 | 442 |
437 // Called by libevent when we can write to the pipe without blocking. | 443 // Called by libevent when we can write to the pipe without blocking. |
438 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { | 444 void Channel::ChannelImpl::OnFileWriteReady(int fd) { |
439 if (!ProcessOutgoingMessages()) { | 445 if (!ProcessOutgoingMessages()) { |
440 Close(); | 446 Close(); |
441 listener_->OnChannelError(); | 447 listener_->OnChannelError(); |
442 } | 448 } |
443 } | 449 } |
444 | 450 |
445 void Channel::ChannelImpl::Close() { | 451 void Channel::ChannelImpl::Close() { |
446 // Close can be called multiple time, so we need to make sure we're | 452 // Close can be called multiple time, so we need to make sure we're |
447 // idempotent. | 453 // idempotent. |
448 | 454 |
449 // Unregister libevent for the listening socket and close it. | 455 // Unregister libevent for the listening socket and close it. |
450 server_listen_connection_watcher_.StopWatchingFileDescriptor(); | 456 if (server_listen_connection_event_ && |
| 457 server_listen_connection_event_->is_active) { |
| 458 MessageLoopForIO::current()->UnwatchFileHandle( |
| 459 &(server_listen_connection_event_->event)); |
| 460 } |
451 | 461 |
452 if (server_listen_pipe_ != -1) { | 462 if (server_listen_pipe_ != -1) { |
453 close(server_listen_pipe_); | 463 close(server_listen_pipe_); |
454 server_listen_pipe_ = -1; | 464 server_listen_pipe_ = -1; |
455 } | 465 } |
456 | 466 |
457 // Unregister libevent for the FIFO and close it. | 467 // Unregister libevent for the FIFO and close it. |
458 read_watcher_.StopWatchingFileDescriptor(); | 468 if (read_event_ && read_event_->is_active) { |
459 write_watcher_.StopWatchingFileDescriptor(); | 469 MessageLoopForIO::current()->UnwatchFileHandle(&(read_event_->event)); |
| 470 } |
| 471 if (write_event_ && write_event_->is_active) { |
| 472 MessageLoopForIO::current()->UnwatchFileHandle(&(write_event_->event)); |
| 473 } |
460 if (pipe_ != -1) { | 474 if (pipe_ != -1) { |
461 close(pipe_); | 475 close(pipe_); |
462 pipe_ = -1; | 476 pipe_ = -1; |
463 } | 477 } |
464 | 478 |
| 479 delete server_listen_connection_event_; |
| 480 server_listen_connection_event_ = NULL; |
| 481 delete read_event_; |
| 482 read_event_ = NULL; |
| 483 delete write_event_; |
| 484 write_event_ = NULL; |
| 485 |
465 // Unlink the FIFO | 486 // Unlink the FIFO |
466 unlink(pipe_name_.c_str()); | 487 unlink(pipe_name_.c_str()); |
467 | 488 |
468 while (!output_queue_.empty()) { | 489 while (!output_queue_.empty()) { |
469 Message* m = output_queue_.front(); | 490 Message* m = output_queue_.front(); |
470 output_queue_.pop(); | 491 output_queue_.pop(); |
471 delete m; | 492 delete m; |
472 } | 493 } |
473 } | 494 } |
474 | 495 |
(...skipping 18 matching lines...) Expand all Loading... |
493 | 514 |
494 void Channel::set_listener(Listener* listener) { | 515 void Channel::set_listener(Listener* listener) { |
495 channel_impl_->set_listener(listener); | 516 channel_impl_->set_listener(listener); |
496 } | 517 } |
497 | 518 |
498 bool Channel::Send(Message* message) { | 519 bool Channel::Send(Message* message) { |
499 return channel_impl_->Send(message); | 520 return channel_impl_->Send(message); |
500 } | 521 } |
501 | 522 |
502 } // namespace IPC | 523 } // namespace IPC |
OLD | NEW |