Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
        }
    }
}
Ejemplo n.º 3
0
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();
}
Ejemplo n.º 4
0
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();
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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();
    }
}