summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/ipc_channel_posix.cc152
-rw-r--r--ipc/ipc_channel_posix.h37
2 files changed, 108 insertions, 81 deletions
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
index 5730153..1960cb0 100644
--- a/ipc/ipc_channel_posix.cc
+++ b/ipc/ipc_channel_posix.cc
@@ -479,48 +479,68 @@ bool Channel::ChannelImpl::Connect() {
}
bool Channel::ChannelImpl::ProcessIncomingMessages() {
- for (;;) {
- if (pipe_ == -1)
+ while (true) {
+ int bytes_read = 0;
+ ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize,
+ &bytes_read);
+ if (read_state == READ_FAILED)
return false;
+ if (read_state == READ_PENDING)
+ return true;
- const char* p = NULL;
- const char* end = NULL;
- if (!ReadDataFromPipe(&p, &end))
- return false; // Pipe error.
- if (!p)
- return true; // No data waiting.
-
- // Dispatch all complete messages in the data buffer.
- while (p < end) {
- const char* message_tail = Message::FindNext(p, end);
- if (message_tail) {
- int len = static_cast<int>(message_tail - p);
- Message m(p, len);
- if (!PopulateMessageFileDescriptors(&m))
- return false;
+ DCHECK(bytes_read > 0);
+ if (!DispatchInputData(input_buf_, bytes_read))
+ return false;
+ }
+}
- DVLOG(2) << "received message on channel @" << this
- << " with type " << m.type() << " on fd " << pipe_;
- if (IsHelloMessage(&m))
- HandleHelloMessage(m);
- else
- listener_->OnMessageReceived(m);
- p = message_tail;
- } else {
- // Last message is partial.
- break;
- }
- }
- input_overflow_buf_.assign(p, end - p);
+bool Channel::ChannelImpl::DispatchInputData(const char* input_data,
+ int input_data_len) {
+ const char* p;
+ const char* end;
- // When the input data buffer is empty, the fds should be too. If this is
- // not the case, we probably have a rogue renderer which is trying to fill
- // our descriptor table.
- if (input_overflow_buf_.empty() && !input_fds_.empty()) {
- // We close these descriptors in Close()
+ // Possibly combine with the overflow buffer to make a larger buffer.
+ if (input_overflow_buf_.empty()) {
+ p = input_data;
+ end = input_data + input_data_len;
+ } else {
+ if (input_overflow_buf_.size() >
+ kMaximumMessageSize - input_data_len) {
+ input_overflow_buf_.clear();
+ LOG(ERROR) << "IPC message is too big";
return false;
}
+ input_overflow_buf_.append(input_data, input_data_len);
+ p = input_overflow_buf_.data();
+ end = p + input_overflow_buf_.size();
}
+
+ // Dispatch all complete messages in the data buffer.
+ while (p < end) {
+ const char* message_tail = Message::FindNext(p, end);
+ if (message_tail) {
+ int len = static_cast<int>(message_tail - p);
+ Message m(p, len);
+ if (!WillDispatchInputMessage(&m))
+ return false;
+
+ if (IsHelloMessage(&m))
+ HandleHelloMessage(m);
+ else
+ listener_->OnMessageReceived(m);
+ p = message_tail;
+ } else {
+ // Last message is partial.
+ break;
+ }
+ }
+
+ // Save any partial data in the overflow buffer.
+ input_overflow_buf_.assign(p, end - p);
+
+ if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
+ return false;
+ return true;
}
bool Channel::ChannelImpl::ProcessOutgoingMessages() {
@@ -937,11 +957,16 @@ bool Channel::ChannelImpl::IsHelloMessage(const Message* m) const {
return m->routing_id() == MSG_ROUTING_NONE && m->type() == HELLO_MESSAGE_TYPE;
}
-bool Channel::ChannelImpl::ReadDataFromPipe(const char** buffer_begin,
- const char** buffer_end) {
+Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
+ char* buffer,
+ int buffer_len,
+ int* bytes_read) {
+ if (pipe_ == -1)
+ return READ_FAILED;
+
struct msghdr msg = {0};
- struct iovec iov = {input_buf_, Channel::kReadBufferSize};
+ struct iovec iov = {buffer, buffer_len};
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@@ -949,62 +974,44 @@ bool Channel::ChannelImpl::ReadDataFromPipe(const char** buffer_begin,
// recvmsg() returns 0 if the connection has closed or EAGAIN if no data
// is waiting on the pipe.
- ssize_t bytes_read = 0;
#if defined(IPC_USES_READWRITE)
if (fd_pipe_ >= 0) {
- bytes_read = HANDLE_EINTR(read(pipe_, input_buf_,
- Channel::kReadBufferSize));
+ *bytes_read = HANDLE_EINTR(read(pipe_, buffer, buffer_len));
msg.msg_controllen = 0;
} else
#endif // IPC_USES_READWRITE
{
msg.msg_controllen = sizeof(input_cmsg_buf_);
- bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+ *bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
}
- if (bytes_read < 0) {
+ if (*bytes_read < 0) {
if (errno == EAGAIN) {
- *buffer_begin = *buffer_end = NULL; // Signal no data was read.
- return true;
+ return READ_PENDING;
#if defined(OS_MACOSX)
} else if (errno == EPERM) {
// On OSX, reading from a pipe with no listener returns EPERM
// treat this as a special case to prevent spurious error messages
// to the console.
- return false;
+ return READ_FAILED;
#endif // OS_MACOSX
} else if (errno == ECONNRESET || errno == EPIPE) {
- return false;
+ return READ_FAILED;
} else {
PLOG(ERROR) << "pipe error (" << pipe_ << ")";
- return false;
+ return READ_FAILED;
}
- } else if (bytes_read == 0) {
+ } else if (*bytes_read == 0) {
// The pipe has closed...
- return false;
+ return READ_FAILED;
}
- DCHECK(bytes_read);
+ DCHECK(*bytes_read);
CloseClientFileDescriptor();
// Read any file descriptors from the message.
if (!ExtractFileDescriptorsFromMsghdr(&msg))
- return false;
-
- // Possibly combine with the overflow buffer to make a larger buffer.
- if (input_overflow_buf_.empty()) {
- *buffer_begin = input_buf_;
- *buffer_end = *buffer_begin + bytes_read;
- } else {
- if (input_overflow_buf_.size() > (kMaximumMessageSize - bytes_read)) {
- input_overflow_buf_.clear();
- LOG(ERROR) << "IPC message is too big";
- return false;
- }
- input_overflow_buf_.append(input_buf_, bytes_read);
- *buffer_begin = input_overflow_buf_.data();
- *buffer_end = *buffer_begin + input_overflow_buf_.size();
- }
- return true;
+ return READ_FAILED;
+ return READ_SUCCEEDED;
}
#if defined(IPC_USES_READWRITE)
@@ -1028,7 +1035,7 @@ bool Channel::ChannelImpl::ReadFileDescriptorsFromFDPipe() {
}
#endif
-bool Channel::ChannelImpl::PopulateMessageFileDescriptors(Message* msg) {
+bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
uint16 header_fds = msg->header()->num_fds;
if (!header_fds)
return true; // Nothing to do.
@@ -1070,6 +1077,13 @@ bool Channel::ChannelImpl::PopulateMessageFileDescriptors(Message* msg) {
return true;
}
+bool Channel::ChannelImpl::DidEmptyInputBuffers() {
+ // When the input data buffer is empty, the fds should be too. If this is
+ // not the case, we probably have a rogue renderer which is trying to fill
+ // our descriptor table.
+ return input_fds_.empty();
+}
+
bool Channel::ChannelImpl::ExtractFileDescriptorsFromMsghdr(msghdr* msg) {
// Check that there are any control messages. On OSX, CMSG_FIRSTHDR will
// return an invalid non-NULL pointer in the case that controllen == 0.
diff --git a/ipc/ipc_channel_posix.h b/ipc/ipc_channel_posix.h
index 38f8ba4..7d26e9b 100644
--- a/ipc/ipc_channel_posix.h
+++ b/ipc/ipc_channel_posix.h
@@ -70,6 +70,8 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
#endif // OS_LINUX
private:
+ enum ReadState { READ_SUCCEEDED, READ_FAILED, READ_PENDING };
+
bool CreatePipe(const IPC::ChannelHandle& channel_handle);
bool ProcessIncomingMessages();
@@ -81,18 +83,25 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
void QueueHelloMessage();
bool IsHelloMessage(const Message* m) const;
- // Reads data from the "regular" (non FD) pipe into the input buffers. The
- // two output params will identify the data received.
+ // Populates the given buffer with data from the pipe.
+ //
+ // Returns the state of the read. On READ_SUCCESS, the number of bytes
+ // read will be placed into |*bytes_read| (which can be less than the
+ // buffer size). On READ_FAILED, the channel will be closed.
//
- // On success, returns true. If there is no data waiting, the pointers will
- // both be set to NULL. Otherwise, they'll indicate the data read. This will
- // be inside the input_buf_ for short messages, and for long messages will
- // automatically spill into the input_overflow_buf_. When in non-READWRITE
- // mode this will also load any handles from the message into input_fds_.
+ // If the return value is READ_PENDING, it means that there was no data
+ // ready for reading. The implementation is then responsible for either
+ // calling AsyncReadComplete with the number of bytes read into the
+ // buffer, or ProcessIncomingMessages to try the read again (depending
+ // on whether the platform's async I/O is "try again" or "write
+ // asynchronously into your buffer").
+ ReadState ReadData(char* buffer, int buffer_len, int* bytes_read);
+
+ // Takes the given data received from the IPC channel and dispatches any
+ // fully completed messages.
//
- // On failure, returns false. This means there was some kind of pipe error
- // and we should not continue.
- bool ReadDataFromPipe(const char** begin, const char** end);
+ // Returns true on success. False means channel error.
+ bool DispatchInputData(const char* input_data, int input_data_len);
#if defined(IPC_USES_READWRITE)
// Reads the next message from the fd_pipe_ and appends them to the
@@ -107,7 +116,11 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
//
// This will read from the input_fds_ and read more handles from the FD
// pipe if necessary.
- bool PopulateMessageFileDescriptors(Message* msg);
+ bool WillDispatchInputMessage(Message* msg);
+
+ // Performs post-dispatch checks. Called when all input buffers are empty,
+ // though there could be more data ready to be read from the OS.
+ bool DidEmptyInputBuffers();
// Finds the set of file descriptors in the given message. On success,
// appends the descriptors to the input_fds_ member and returns true
@@ -170,7 +183,7 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
// Messages to be sent are queued here.
std::queue<Message*> output_queue_;
- // We read from the pipe into this buffer. Managed by ReadDataFromPipe, do
+ // We read from the pipe into this buffer. Managed by DispatchInputData, do
// not access directly outside that function.
char input_buf_[Channel::kReadBufferSize];