bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) { ASSERT(m_socket); // We put the message ID last. arguments->encodeUInt32(messageID.toInt()); size_t bufferSize = arguments->bufferSize(); // Write message size first // FIXME: Should just do a single write. qint64 bytesWrittenForSize = m_socket->write(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize)); if (bytesWrittenForSize != sizeof(bufferSize)) { connectionDidClose(); return false; } qint64 bytesWrittenForBuffer = m_socket->write(reinterpret_cast<char*>(arguments->buffer()), arguments->bufferSize()); if (bytesWrittenForBuffer != arguments->bufferSize()) { connectionDidClose(); return false; } m_socket->flush(); return true; }
void Connection::readyReadHandler() { while (true) { size_t fileDescriptorsCount = 0; size_t bytesToRead = m_readBuffer.size() - m_readBufferSize; ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer.data() + m_readBufferSize, bytesToRead, m_fileDescriptors.data() + m_fileDescriptorsSize, &fileDescriptorsCount); if (bytesRead < 0) { // EINTR was already handled by readBytesFromSocket. if (errno == EAGAIN || errno == EWOULDBLOCK) return; WTFLogAlways("Error receiving IPC message on socket %d in process %d: %s", m_socketDescriptor, getpid(), strerror(errno)); connectionDidClose(); return; } m_readBufferSize += bytesRead; m_fileDescriptorsSize += fileDescriptorsCount; if (!bytesRead) { connectionDidClose(); return; } // Process messages from data received. while (true) { if (!processMessage()) break; } } }
void Connection::writeEventHandler() { if (m_connectionPipe == INVALID_HANDLE_VALUE) return; DWORD numberOfBytesWritten = 0; if (!::GetOverlappedResult(m_connectionPipe, &m_writeState, &numberOfBytesWritten, FALSE)) { DWORD error = ::GetLastError(); if (error == ERROR_IO_INCOMPLETE) { // FIXME: We should figure out why we're getting this error. return; } if (error == ERROR_BROKEN_PIPE) { connectionDidClose(); return; } ASSERT_NOT_REACHED(); } // The pending write has finished, so we are now done with its encoder. Clearing this member // will allow us to send messages again. m_pendingWriteEncoder = nullptr; // Now that the pending write has finished, we can try to send a new message. sendOutgoingMessages(); }
void Connection::exceptionSourceEventHandler() { ReceiveBuffer buffer; mach_msg_header_t* header = readFromMachPort(m_exceptionPort, buffer); if (!header) return; // We've read the exception message. Now send it on to the real exception port. // The remote port should have a send once right. ASSERT(MACH_MSGH_BITS_REMOTE(header->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE); // Now get the real exception port. mach_port_t exceptionPort = machExceptionPort(); // First, get the complex bit from the source message. mach_msg_bits_t messageBits = header->msgh_bits & MACH_MSGH_BITS_COMPLEX; messageBits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE); header->msgh_bits = messageBits; header->msgh_local_port = header->msgh_remote_port; header->msgh_remote_port = exceptionPort; // Now send along the message. kern_return_t kr = mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kr != KERN_SUCCESS) { LOG_ERROR("Failed to send message to real exception port. %s (%x)", mach_error_string(kr), kr); ASSERT_NOT_REACHED(); } connectionDidClose(); }
void Connection::readyReadHandler() { while (true) { size_t fileDescriptorsCount = 0; size_t bytesToRead = m_readBuffer.size() - m_readBufferSize; ssize_t bytesRead = readBytesFromSocket(m_socketDescriptor, m_readBuffer.data() + m_readBufferSize, bytesToRead, m_fileDescriptors.data() + m_fileDescriptorsSize, &fileDescriptorsCount); if (bytesRead < 0) { // EINTR was already handled by readBytesFromSocket. if (errno == EAGAIN || errno == EWOULDBLOCK) return; // FIXME: Handle other errors here? return; } m_readBufferSize += bytesRead; m_fileDescriptorsSize += fileDescriptorsCount; if (!bytesRead) { connectionDidClose(); return; } // Process messages from data received. while (true) { if (!processMessage()) break; } } }
void ChildProcessProxy::clearConnection() { if (!m_connection) return; // FIXME: Call this after the connection has been invalidated. connectionDidClose(*m_connection); m_connection->invalidate(); m_connection = nullptr; }
bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<MessageEncoder> encoder) { ASSERT(!m_pendingWriteEncoder); // Just bail if the handle has been closed. if (m_connectionPipe == INVALID_HANDLE_VALUE) return false; // We put the message ID last. encoder->encode(static_cast<uint32_t>(messageID.toInt())); // Write the outgoing message. if (::WriteFile(m_connectionPipe, encoder->buffer(), encoder->bufferSize(), 0, &m_writeState)) { // We successfully sent this message. return true; } DWORD error = ::GetLastError(); if (error == ERROR_NO_DATA) { // The pipe is being closed. connectionDidClose(); return false; } if (error != ERROR_IO_PENDING) { ASSERT_NOT_REACHED(); return false; } // The message will be sent soon. Hold onto the encoder so that it won't be destroyed // before the write completes. m_pendingWriteEncoder = encoder; // We can only send one asynchronous message at a time (see comment in platformCanSendOutgoingMessages). return false; }
void Connection::readEventHandler() { if (m_connectionPipe == INVALID_HANDLE_VALUE) return; while (true) { // Check if we got some data. DWORD numberOfBytesRead = 0; if (!::GetOverlappedResult(m_connectionPipe, &m_readState, &numberOfBytesRead, FALSE)) { DWORD error = ::GetLastError(); switch (error) { case ERROR_BROKEN_PIPE: connectionDidClose(); return; case ERROR_MORE_DATA: { // Read the rest of the message out of the pipe. DWORD bytesToRead = 0; if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { DWORD error = ::GetLastError(); if (error == ERROR_BROKEN_PIPE) { connectionDidClose(); return; } ASSERT_NOT_REACHED(); return; } // ::GetOverlappedResult told us there's more data. ::PeekNamedPipe shouldn't // contradict it! ASSERT(bytesToRead); if (!bytesToRead) break; m_readBuffer.grow(m_readBuffer.size() + bytesToRead); if (!::ReadFile(m_connectionPipe, m_readBuffer.data() + numberOfBytesRead, bytesToRead, 0, &m_readState)) { DWORD error = ::GetLastError(); ASSERT_NOT_REACHED(); return; } continue; } // FIXME: We should figure out why we're getting this error. case ERROR_IO_INCOMPLETE: return; default: ASSERT_NOT_REACHED(); } } if (!m_readBuffer.isEmpty()) { // We have a message, let's dispatch it. // The messageID is encoded at the end of the buffer. // Note that we assume here that the message is the same size as m_readBuffer. We can // assume this because we always size m_readBuffer to exactly match the size of the message, // either when receiving ERROR_MORE_DATA from ::GetOverlappedResult above or when // ::PeekNamedPipe tells us the size below. We never set m_readBuffer to a size larger // than the message. ASSERT(m_readBuffer.size() >= sizeof(MessageID)); size_t realBufferSize = m_readBuffer.size() - sizeof(MessageID); unsigned messageID = *reinterpret_cast<unsigned*>(m_readBuffer.data() + realBufferSize); OwnPtr<MessageDecoder> decoder = MessageDecoder::create(DataReference(m_readBuffer.data(), realBufferSize)); processIncomingMessage(MessageID::fromInt(messageID), decoder.release()); } // Find out the size of the next message in the pipe (if there is one) so that we can read // it all in one operation. (This is just an optimization to avoid an extra pass through the // loop (if we chose a buffer size that was too small) or allocating extra memory (if we // chose a buffer size that was too large).) DWORD bytesToRead = 0; if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { DWORD error = ::GetLastError(); if (error == ERROR_BROKEN_PIPE) { connectionDidClose(); return; } ASSERT_NOT_REACHED(); } if (!bytesToRead) { // There's no message waiting in the pipe. Schedule a read of the first byte of the // next message. We'll find out the message's actual size when it arrives. (If we // change this to read more than a single byte for performance reasons, we'll have to // deal with m_readBuffer potentially being larger than the message we read after // calling ::GetOverlappedResult above.) bytesToRead = 1; } m_readBuffer.resize(bytesToRead); // Either read the next available message (which should occur synchronously), or start an // asynchronous read of the next message that becomes available. BOOL result = ::ReadFile(m_connectionPipe, m_readBuffer.data(), m_readBuffer.size(), 0, &m_readState); if (result) { // There was already a message waiting in the pipe, and we read it synchronously. // Process it. continue; } DWORD error = ::GetLastError(); if (error == ERROR_IO_PENDING) { // There are no messages in the pipe currently. readEventHandler will be called again once there is a message. return; } if (error == ERROR_MORE_DATA) { // Either a message is available when we didn't think one was, or the message is larger // than ::PeekNamedPipe told us. The former seems far more likely. Probably the message // became available between our calls to ::PeekNamedPipe and ::ReadFile above. Go back // to the top of the loop to use ::GetOverlappedResult to retrieve the available data. continue; } // FIXME: We need to handle other errors here. ASSERT_NOT_REACHED(); } }