diff options
Diffstat (limited to 'Source/WebKit2/Platform/CoreIPC')
24 files changed, 4328 insertions, 0 deletions
diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentCoder.h b/Source/WebKit2/Platform/CoreIPC/ArgumentCoder.h new file mode 100644 index 0000000..bd15f51 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentCoder.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ArgumentCoder_h +#define ArgumentCoder_h + +#include <wtf/TypeTraits.h> + +namespace CoreIPC { + +class ArgumentDecoder; +class ArgumentEncoder; + +template<typename T> struct ArgumentCoder { + static void encode(ArgumentEncoder* encoder, const T& t) + { + t.encode(encoder); + } + + static bool decode(ArgumentDecoder* decoder, T& t) + { + return T::decode(decoder, t); + } +}; + +} + +#endif // ArgumentCoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentCoders.h b/Source/WebKit2/Platform/CoreIPC/ArgumentCoders.h new file mode 100644 index 0000000..1cc1a7d --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentCoders.h @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SimpleArgumentCoder_h +#define SimpleArgumentCoder_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include <utility> +#include <wtf/HashMap.h> +#include <wtf/TypeTraits.h> +#include <wtf/Vector.h> +#include <wtf/text/AtomicString.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace CoreIPC { + +// An argument coder works on POD types +template<typename T> struct SimpleArgumentCoder { + static void encode(ArgumentEncoder* encoder, const T& t) + { + encoder->encodeBytes(reinterpret_cast<const uint8_t*>(&t), sizeof(T)); + } + static bool decode(ArgumentDecoder* decoder, T& t) + { + return decoder->decodeBytes(reinterpret_cast<uint8_t*>(&t), sizeof(T)); + } +}; + +template<typename T, typename U> struct ArgumentCoder<std::pair<T, U> > { + static void encode(ArgumentEncoder* encoder, const std::pair<T, U>& pair) + { + encoder->encode(pair.first); + encoder->encode(pair.second); + } + + static bool decode(ArgumentDecoder* decoder, std::pair<T, U>& pair) + { + T first; + if (!decoder->decode(first)) + return false; + + U second; + if (!decoder->decode(second)) + return false; + + pair.first = first; + pair.second = second; + return true; + } +}; + +template<bool fixedSizeElements, typename T> struct VectorArgumentCoder; + +template<typename T> struct VectorArgumentCoder<false, T> { + static void encode(ArgumentEncoder* encoder, const Vector<T>& vector) + { + encoder->encodeUInt64(vector.size()); + for (size_t i = 0; i < vector.size(); ++i) + encoder->encode(vector[i]); + } + + static bool decode(ArgumentDecoder* decoder, Vector<T>& vector) + { + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + Vector<T> tmp; + for (size_t i = 0; i < size; ++i) { + T element; + if (!decoder->decode(element)) + return false; + + tmp.append(element); + } + + tmp.shrinkToFit(); + vector.swap(tmp); + return true; + } +}; + +template<typename T> struct VectorArgumentCoder<true, T> { + static void encode(ArgumentEncoder* encoder, const Vector<T>& vector) + { + encoder->encodeUInt64(vector.size()); + // FIXME: If we could tell the encoder to align the buffer, we could just do an encodeBytes here. + for (size_t i = 0; i < vector.size(); ++i) + encoder->encode(vector[i]); + } + + static bool decode(ArgumentDecoder* decoder, Vector<T>& vector) + { + uint64_t size; + if (!decoder->decodeUInt64(size)) + return false; + + // Since we know the total size of the elements, we can allocate the vector in + // one fell swoop. Before allocating we must however make sure that the decoder buffer + // is big enough. + if (!decoder->bufferIsLargeEnoughToContain<T>(size)) { + decoder->markInvalid(); + return false; + } + + Vector<T> tmp; + tmp.reserveCapacity(size); + + for (size_t i = 0; i < size; ++i) { + T element; + if (!decoder->decode(element)) + return false; + + tmp.uncheckedAppend(element); + } + + vector.swap(tmp); + return true; + } +}; + +template<typename T> struct ArgumentCoder<Vector<T> > : VectorArgumentCoder<WTF::IsArithmetic<T>::value, T> { }; + +// Specialization for Vector<uint8_t> +template<> struct ArgumentCoder<Vector<uint8_t> > { + static void encode(ArgumentEncoder* encoder, const Vector<uint8_t>& vector) + { + encoder->encodeBytes(vector.data(), vector.size()); + } + + static bool decode(ArgumentDecoder* decoder, Vector<uint8_t>& vector) + { + return decoder->decodeBytes(vector); + } +}; + +template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> struct ArgumentCoder<HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> > { + typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMapType; + + static void encode(ArgumentEncoder* encoder, const HashMapType& hashMap) + { + encoder->encodeUInt64(hashMap.size()); + for (typename HashMapType::const_iterator it = hashMap.begin(), end = hashMap.end(); it != end; ++it) + encoder->encode(*it); + } + + static bool decode(ArgumentDecoder* decoder, HashMapType& hashMap) + { + uint64_t hashMapSize; + if (!decoder->decode(hashMapSize)) + return false; + + HashMapType tempHashMap; + for (uint64_t i = 0; i < hashMapSize; ++i) { + KeyArg key; + MappedArg value; + if (!decoder->decode(key)) + return false; + if (!decoder->decode(value)) + return false; + + if (!tempHashMap.add(key, value).second) { + // The hash map already has the specified key, bail. + decoder->markInvalid(); + return false; + } + } + + hashMap.swap(tempHashMap); + return true; + } +}; + +template<> struct ArgumentCoder<CString> { + static void encode(ArgumentEncoder* encoder, const CString& string) + { + // Special case the null string. + if (string.isNull()) { + encoder->encodeUInt32(std::numeric_limits<uint32_t>::max()); + return; + } + + uint32_t length = string.length(); + encoder->encode(length); + encoder->encodeBytes(reinterpret_cast<const uint8_t*>(string.data()), length); + } + + static bool decode(ArgumentDecoder* decoder, CString& result) + { + uint32_t length; + if (!decoder->decode(length)) + return false; + + if (length == std::numeric_limits<uint32_t>::max()) { + // This is the null string. + result = CString(); + return true; + } + + // Before allocating the string, make sure that the decoder buffer is big enough. + if (!decoder->bufferIsLargeEnoughToContain<char>(length)) { + decoder->markInvalid(); + return false; + } + + char* buffer; + CString string = CString::newUninitialized(length, buffer); + if (!decoder->decodeBytes(reinterpret_cast<uint8_t*>(buffer), length)) + return false; + + result = string; + return true; + } +}; + +template<> struct ArgumentCoder<String> { + static void encode(ArgumentEncoder* encoder, const String& string) + { + // Special case the null string. + if (string.isNull()) { + encoder->encodeUInt32(std::numeric_limits<uint32_t>::max()); + return; + } + + uint32_t length = string.length(); + encoder->encode(length); + encoder->encodeBytes(reinterpret_cast<const uint8_t*>(string.characters()), length * sizeof(UChar)); + } + + static bool decode(ArgumentDecoder* decoder, String& result) + { + uint32_t length; + if (!decoder->decode(length)) + return false; + + if (length == std::numeric_limits<uint32_t>::max()) { + // This is the null string. + result = String(); + return true; + } + + // Before allocating the string, make sure that the decoder buffer is big enough. + if (!decoder->bufferIsLargeEnoughToContain<UChar>(length)) { + decoder->markInvalid(); + return false; + } + + UChar* buffer; + String string = String::createUninitialized(length, buffer); + if (!decoder->decodeBytes(reinterpret_cast<uint8_t*>(buffer), length * sizeof(UChar))) + return false; + + result = string; + return true; + } +}; + +template<> struct ArgumentCoder<AtomicString> { + static void encode(ArgumentEncoder* encoder, const AtomicString& atomicString) + { + encoder->encode(atomicString.string()); + } + + static bool decode(ArgumentDecoder* decoder, AtomicString& atomicString) + { + String string; + if (!decoder->decode(string)) + return false; + + atomicString = string; + return true; + } +}; + +} // namespace CoreIPC + +#endif // SimpleArgumentCoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp new file mode 100644 index 0000000..336f72f --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ArgumentDecoder.h" + +#include "DataReference.h" +#include <stdio.h> + +namespace CoreIPC { + +ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize) +{ + initialize(buffer, bufferSize); +} + +ArgumentDecoder::ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Deque<Attachment>& attachments) +{ + initialize(buffer, bufferSize); + + m_attachments.swap(attachments); +} + +ArgumentDecoder::~ArgumentDecoder() +{ + ASSERT(m_buffer); + fastFree(m_buffer); + // FIXME: We need to dispose of the mach ports in cases of failure. +} + +void ArgumentDecoder::initialize(const uint8_t* buffer, size_t bufferSize) +{ + m_buffer = static_cast<uint8_t*>(fastMalloc(bufferSize)); + m_bufferPos = m_buffer; + m_bufferEnd = m_buffer + bufferSize; + memcpy(m_buffer, buffer, bufferSize); + + // Decode the destination ID. + decodeUInt64(m_destinationID); +} + +static inline uint8_t* roundUpToAlignment(uint8_t* ptr, unsigned alignment) +{ + return (uint8_t*)(((uintptr_t)ptr + alignment - 1) & ~(uintptr_t)(alignment - 1)); +} + +bool ArgumentDecoder::alignBufferPosition(unsigned alignment, size_t size) +{ + uint8_t* buffer = roundUpToAlignment(m_bufferPos, alignment); + if (buffer + size > m_bufferEnd) { + // We've walked off the end of this buffer. + markInvalid(); + return false; + } + + m_bufferPos = buffer; + return true; +} + +bool ArgumentDecoder::bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const +{ + return roundUpToAlignment(m_bufferPos, alignment) + size <= m_bufferEnd; +} + +bool ArgumentDecoder::decodeBytes(Vector<uint8_t>& buffer) +{ + uint64_t size; + if (!decodeUInt64(size)) + return false; + + if (!alignBufferPosition(1, size)) + return false; + + buffer.resize(size); + if (size > 0) + memcpy(&buffer[0], m_bufferPos, size); + m_bufferPos += size; + return true; +} + +bool ArgumentDecoder::decodeBytes(DataReference& dataReference) +{ + uint64_t size; + if (!decodeUInt64(size)) + return false; + + if (!alignBufferPosition(1, size)) + return false; + + uint8_t* data = m_bufferPos; + m_bufferPos += size; + + dataReference = DataReference(data, size); + return true; +} + +bool ArgumentDecoder::decodeBytes(uint8_t* buffer, size_t bufferSize) +{ + // FIXME: Decoding the size is not strictly necessary here since we know the size upfront. + uint64_t size; + if (!decodeUInt64(size)) + return false; + + ASSERT(size == bufferSize); + if (size != bufferSize) + return false; + + if (!alignBufferPosition(1, size)) + return false; + + memcpy(buffer, m_bufferPos, size); + m_bufferPos += size; + return true; +} + +bool ArgumentDecoder::decodeBool(bool& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<bool*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeUInt32(uint32_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint32_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeUInt64(uint64_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint64_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeInt32(int32_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint32_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeInt64(int64_t& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<uint64_t*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeFloat(float& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<float*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::decodeDouble(double& result) +{ + if (!alignBufferPosition(__alignof(result), sizeof(result))) + return false; + + result = *reinterpret_cast<double*>(m_bufferPos); + m_bufferPos += sizeof(result); + return true; +} + +bool ArgumentDecoder::removeAttachment(Attachment& attachment) +{ + if (m_attachments.isEmpty()) + return false; + + attachment = m_attachments.takeFirst(); + return true; +} + +#ifndef NDEBUG +void ArgumentDecoder::debug() +{ + printf("ArgumentDecoder::debug()\n"); + printf("Number of Attachments: %d\n", (int)m_attachments.size()); + printf("Size of buffer: %d\n", (int)(m_bufferEnd - m_buffer)); +} +#endif + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.h b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.h new file mode 100644 index 0000000..dcf67ad --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ArgumentDecoder_h +#define ArgumentDecoder_h + +#include "ArgumentCoder.h" +#include "Attachment.h" +#include <wtf/Deque.h> +#include <wtf/TypeTraits.h> +#include <wtf/Vector.h> + +namespace CoreIPC { + +class DataReference; + +class ArgumentDecoder { +public: + ArgumentDecoder(const uint8_t* buffer, size_t bufferSize); + ArgumentDecoder(const uint8_t* buffer, size_t bufferSize, Deque<Attachment>&); + ~ArgumentDecoder(); + + uint64_t destinationID() const { return m_destinationID; } + + bool isInvalid() const { return m_bufferPos > m_bufferEnd; } + void markInvalid() { m_bufferPos = m_bufferEnd + 1; } + + bool decodeBytes(Vector<uint8_t>&); + bool decodeBytes(uint8_t*, size_t); + + // The data in the data reference here will only be valid for the lifetime of the ArgumentDecoder object. + bool decodeBytes(DataReference&); + + bool decodeBool(bool&); + bool decodeUInt32(uint32_t&); + bool decodeUInt64(uint64_t&); + bool decodeInt32(int32_t&); + bool decodeInt64(int64_t&); + bool decodeFloat(float&); + bool decodeDouble(double&); + + template<typename T> bool decodeEnum(T& result) + { + COMPILE_ASSERT(sizeof(T) <= sizeof(uint64_t), enum_type_must_not_be_larger_than_64_bits); + + uint64_t value; + if (!decodeUInt64(value)) + return false; + + result = static_cast<T>(value); + return true; + } + + template<typename T> + bool bufferIsLargeEnoughToContain(size_t numElements) const + { + COMPILE_ASSERT(WTF::IsArithmetic<T>::value, type_must_have_known_encoded_size); + + if (numElements > std::numeric_limits<size_t>::max() / sizeof(T)) + return false; + + return bufferIsLargeEnoughToContain(__alignof(T), numElements * sizeof(T)); + } + + // Generic type decode function. + template<typename T> bool decode(T& t) + { + return ArgumentCoder<T>::decode(this, t); + } + + // This overload exists so we can pass temporaries to decode. In the Star Trek future, it + // can take an rvalue reference instead. + template<typename T> bool decode(const T& t) + { + return decode(const_cast<T&>(t)); + } + + bool removeAttachment(Attachment&); + +#ifndef NDEBUG + void debug(); +#endif + +private: + ArgumentDecoder(const ArgumentDecoder*); + ArgumentDecoder* operator=(const ArgumentDecoder*); + + void initialize(const uint8_t* buffer, size_t bufferSize); + + bool alignBufferPosition(unsigned alignment, size_t size); + bool bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const; + + uint64_t m_destinationID; + + uint8_t* m_buffer; + uint8_t* m_bufferPos; + uint8_t* m_bufferEnd; + + Deque<Attachment> m_attachments; +}; + +template<> inline bool ArgumentDecoder::decode(bool& n) +{ + return decodeBool(n); +} + +template<> inline bool ArgumentDecoder::decode(uint32_t& n) +{ + return decodeUInt32(n); +} + +template<> inline bool ArgumentDecoder::decode(uint64_t& n) +{ + return decodeUInt64(n); +} + +template<> inline bool ArgumentDecoder::decode(int32_t& n) +{ + return decodeInt32(n); +} + +template<> inline bool ArgumentDecoder::decode(int64_t& n) +{ + return decodeInt64(n); +} + +template<> inline bool ArgumentDecoder::decode(float& n) +{ + return decodeFloat(n); +} + +template<> inline bool ArgumentDecoder::decode(double& n) +{ + return decodeDouble(n); +} + +} // namespace CoreIPC + +#endif // ArgumentDecoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp new file mode 100644 index 0000000..1340c0a --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ArgumentEncoder.h" + +#include <algorithm> +#include <stdio.h> + +namespace CoreIPC { + +PassOwnPtr<ArgumentEncoder> ArgumentEncoder::create(uint64_t destinationID) +{ + return adoptPtr(new ArgumentEncoder(destinationID)); +} + +ArgumentEncoder::ArgumentEncoder(uint64_t destinationID) + : m_buffer(0) + , m_bufferPointer(0) + , m_bufferSize(0) + , m_bufferCapacity(0) +{ + // Encode the destination ID. + encodeUInt64(destinationID); +} + +ArgumentEncoder::~ArgumentEncoder() +{ + if (m_buffer) + fastFree(m_buffer); + // FIXME: We need to dispose of the attachments in cases of failure. +} + +static inline size_t roundUpToAlignment(size_t value, unsigned alignment) +{ + return ((value + alignment - 1) / alignment) * alignment; +} + +uint8_t* ArgumentEncoder::grow(unsigned alignment, size_t size) +{ + size_t alignedSize = roundUpToAlignment(m_bufferSize, alignment); + + if (alignedSize + size > m_bufferCapacity) { + size_t newCapacity = std::max(alignedSize + size, std::max(static_cast<size_t>(32), m_bufferCapacity + m_bufferCapacity / 4 + 1)); + if (!m_buffer) + m_buffer = static_cast<uint8_t*>(fastMalloc(newCapacity)); + else + m_buffer = static_cast<uint8_t*>(fastRealloc(m_buffer, newCapacity)); + + // FIXME: What should we do if allocating memory fails? + + m_bufferCapacity = newCapacity; + } + + m_bufferSize = alignedSize + size; + m_bufferPointer = m_buffer + alignedSize + size; + + return m_buffer + alignedSize; +} + +void ArgumentEncoder::encodeBytes(const uint8_t* bytes, size_t size) +{ + // Encode the size. + encodeUInt64(static_cast<uint64_t>(size)); + + uint8_t* buffer = grow(1, size); + + memcpy(buffer, bytes, size); +} + +void ArgumentEncoder::encodeBool(bool n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<bool*>(buffer) = n; +} + +void ArgumentEncoder::encodeUInt32(uint32_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<uint32_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeUInt64(uint64_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<uint64_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeInt32(int32_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<int32_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeInt64(int64_t n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<int64_t*>(buffer) = n; +} + +void ArgumentEncoder::encodeFloat(float n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<float*>(buffer) = n; +} + +void ArgumentEncoder::encodeDouble(double n) +{ + uint8_t* buffer = grow(__alignof(n), sizeof(n)); + + *reinterpret_cast<double*>(buffer) = n; +} + +void ArgumentEncoder::addAttachment(const Attachment& attachment) +{ + m_attachments.append(attachment); +} + +Vector<Attachment> ArgumentEncoder::releaseAttachments() +{ + Vector<Attachment> newList; + newList.swap(m_attachments); + return newList; +} + +#ifndef NDEBUG +void ArgumentEncoder::debug() +{ + printf("ArgumentEncoder::debug()\n"); + printf("Number of Attachments: %d\n", (int)m_attachments.size()); + printf("Size of buffer: %d\n", (int)m_bufferSize); +} +#endif + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.h b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.h new file mode 100644 index 0000000..97f0262 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ArgumentEncoder_h +#define ArgumentEncoder_h + +#include "ArgumentCoder.h" +#include "Attachment.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/TypeTraits.h> +#include <wtf/Vector.h> + +namespace CoreIPC { + +class ArgumentEncoder; + +class ArgumentEncoder { +public: + static PassOwnPtr<ArgumentEncoder> create(uint64_t destinationID); + ~ArgumentEncoder(); + + void encodeBytes(const uint8_t*, size_t); + + void encodeBool(bool); + void encodeUInt32(uint32_t); + void encodeUInt64(uint64_t); + void encodeInt32(int32_t); + void encodeInt64(int64_t); + void encodeFloat(float); + void encodeDouble(double); + + template<typename T> void encodeEnum(T t) + { + COMPILE_ASSERT(sizeof(T) <= sizeof(uint64_t), enum_type_must_not_be_larger_than_64_bits); + + encodeUInt64(static_cast<uint64_t>(t)); + } + + // Generic type encode function. + template<typename T> void encode(const T& t) + { + ArgumentCoder<T>::encode(this, t); + } + + uint8_t* buffer() const { return m_buffer; } + size_t bufferSize() const { return m_bufferSize; } + + void addAttachment(const Attachment&); + Vector<Attachment> releaseAttachments(); + +#ifndef NDEBUG + void debug(); +#endif + +private: + explicit ArgumentEncoder(uint64_t destinationID); + uint8_t* grow(unsigned alignment, size_t size); + + uint8_t* m_buffer; + uint8_t* m_bufferPointer; + + size_t m_bufferSize; + size_t m_bufferCapacity; + + Vector<Attachment> m_attachments; +}; + +template<> inline void ArgumentEncoder::encode(const bool& n) +{ + encodeBool(n); +} + +template<> inline void ArgumentEncoder::encode(const uint32_t& n) +{ + encodeUInt32(n); +} + +template<> inline void ArgumentEncoder::encode(const uint64_t& n) +{ + encodeUInt64(n); +} + +template<> inline void ArgumentEncoder::encode(const int32_t& n) +{ + encodeInt32(n); +} + +template<> inline void ArgumentEncoder::encode(const int64_t& n) +{ + encodeInt64(n); +} + +template<> inline void ArgumentEncoder::encode(const float& n) +{ + encodeFloat(n); +} + +template<> inline void ArgumentEncoder::encode(const double& n) +{ + encodeDouble(n); +} + +} // namespace CoreIPC + +#endif // ArgumentEncoder_h diff --git a/Source/WebKit2/Platform/CoreIPC/Arguments.h b/Source/WebKit2/Platform/CoreIPC/Arguments.h new file mode 100644 index 0000000..ba7c7e8 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Arguments.h @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Arguments_h +#define Arguments_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include <wtf/TypeTraits.h> + +namespace CoreIPC { + +struct Arguments0 { + typedef Arguments0 ValueType; + + void encode(ArgumentEncoder*) const + { + } + + static bool decode(ArgumentDecoder*, Arguments0&) + { + return true; + } +}; + +inline Arguments0 In() +{ + return Arguments0(); +} + +inline Arguments0 Out() +{ + return Arguments0(); +} + +template<typename T1> struct Arguments1 { + typedef Arguments1<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type> ValueType; + + Arguments1() + { + } + + Arguments1(T1 t1) + : argument1(t1) + { + } + + void encode(ArgumentEncoder* encoder) const + { + encoder->encode(argument1); + } + + static bool decode(ArgumentDecoder* decoder, Arguments1& result) + { + return decoder->decode(result.argument1); + } + + T1 argument1; +}; + +template<typename T1> Arguments1<const T1&> In(const T1& t1) +{ + return Arguments1<const T1&>(t1); +} + +template<typename T1> Arguments1<T1&> Out(T1& t1) +{ + return Arguments1<T1&>(t1); +} + +template<typename T1, typename T2> struct Arguments2 : Arguments1<T1> { + typedef Arguments2<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type> ValueType; + + Arguments2() + { + } + + Arguments2(T1 t1, T2 t2) + : Arguments1<T1>(t1) + , argument2(t2) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments1<T1>::encode(encoder); + encoder->encode(argument2); + } + + static bool decode(ArgumentDecoder* decoder, Arguments2& result) + { + if (!Arguments1<T1>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument2); + } + + T2 argument2; +}; + +template<typename T1, typename T2> Arguments2<const T1&, const T2&> In(const T1& t1, const T2& t2) +{ + return Arguments2<const T1&, const T2&>(t1, t2); +} + +template<typename T1, typename T2> Arguments2<T1&, T2&> Out(T1& t1, T2& t2) +{ + return Arguments2<T1&, T2&>(t1, t2); +} + +template<typename T1, typename T2, typename T3> struct Arguments3 : Arguments2<T1, T2> { + typedef Arguments3<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type> ValueType; + + Arguments3() + { + } + + Arguments3(T1 t1, T2 t2, T3 t3) + : Arguments2<T1, T2>(t1, t2) + , argument3(t3) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments2<T1, T2>::encode(encoder); + encoder->encode(argument3); + } + + static bool decode(ArgumentDecoder* decoder, Arguments3& result) + { + if (!Arguments2<T1, T2>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument3); + } + + T3 argument3; +}; + +template<typename T1, typename T2, typename T3> Arguments3<const T1&, const T2&, const T3&> In(const T1& t1, const T2& t2, const T3 &t3) +{ + return Arguments3<const T1&, const T2&, const T3&>(t1, t2, t3); +} + +template<typename T1, typename T2, typename T3> Arguments3<T1&, T2&, T3&> Out(T1& t1, T2& t2, T3& t3) +{ + return Arguments3<T1&, T2&, T3&>(t1, t2, t3); +} + +template<typename T1, typename T2, typename T3, typename T4> struct Arguments4 : Arguments3<T1, T2, T3> { + typedef Arguments4<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type> ValueType; + + Arguments4() + { + } + + Arguments4(T1 t1, T2 t2, T3 t3, T4 t4) + : Arguments3<T1, T2, T3>(t1, t2, t3) + , argument4(t4) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments3<T1, T2, T3>::encode(encoder); + encoder->encode(argument4); + } + + static bool decode(ArgumentDecoder* decoder, Arguments4& result) + { + if (!Arguments3<T1, T2, T3>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument4); + } + + T4 argument4; +}; + +template<typename T1, typename T2, typename T3, typename T4> Arguments4<const T1&, const T2&, const T3&, const T4&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4) +{ + return Arguments4<const T1&, const T2&, const T3&, const T4&>(t1, t2, t3, t4); +} + +template<typename T1, typename T2, typename T3, typename T4> Arguments4<T1&, T2&, T3&, T4&> Out(T1& t1, T2& t2, T3& t3, T4& t4) +{ + return Arguments4<T1&, T2&, T3&, T4&>(t1, t2, t3, t4); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5> struct Arguments5 : Arguments4<T1, T2, T3, T4> { + typedef Arguments5<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type> ValueType; + + Arguments5() + { + } + + Arguments5(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + : Arguments4<T1, T2, T3, T4>(t1, t2, t3, t4) + , argument5(t5) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments4<T1, T2, T3, T4>::encode(encoder); + encoder->encode(argument5); + } + + static bool decode(ArgumentDecoder* decoder, Arguments5& result) + { + if (!Arguments4<T1, T2, T3, T4>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument5); + } + + T5 argument5; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5> Arguments5<const T1&, const T2&, const T3&, const T4&, const T5&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5) +{ + return Arguments5<const T1&, const T2&, const T3&, const T4&, const T5&>(t1, t2, t3, t4, t5); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5> Arguments5<T1&, T2&, T3&, T4&, T5&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) +{ + return Arguments5<T1&, T2&, T3&, T4&, T5&>(t1, t2, t3, t4, t5); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> struct Arguments6 : Arguments5<T1, T2, T3, T4, T5> { + typedef Arguments6<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T6>::Type>::Type> ValueType; + + Arguments6() + { + } + + Arguments6(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + : Arguments5<T1, T2, T3, T4, T5>(t1, t2, t3, t4, t5) + , argument6(t6) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments5<T1, T2, T3, T4, T5>::encode(encoder); + encoder->encode(argument6); + } + + static bool decode(ArgumentDecoder* decoder, Arguments6& result) + { + if (!Arguments5<T1, T2, T3, T4, T5>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument6); + } + + T6 argument6; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> Arguments6<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5, const T6& t6) +{ + return Arguments6<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&>(t1, t2, t3, t4, t5, t6); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> Arguments6<T1&, T2&, T3&, T4&, T5&, T6&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) +{ + return Arguments6<T1&, T2&, T3&, T4&, T5&, T6&>(t1, t2, t3, t4, t5, t6); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> struct Arguments7 : Arguments6<T1, T2, T3, T4, T5, T6> { + typedef Arguments7<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T6>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T7>::Type>::Type> ValueType; + + Arguments7() + { + } + + Arguments7(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + : Arguments6<T1, T2, T3, T4, T5, T6>(t1, t2, t3, t4, t5, t6) + , argument7(t7) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments6<T1, T2, T3, T4, T5, T6>::encode(encoder); + encoder->encode(argument7); + } + + static bool decode(ArgumentDecoder* decoder, Arguments7& result) + { + if (!Arguments6<T1, T2, T3, T4, T5, T6>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument7); + } + + T7 argument7; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> Arguments7<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7) +{ + return Arguments7<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&>(t1, t2, t3, t4, t5, t6, t7); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> Arguments7<T1&, T2&, T3&, T4&, T5&, T6&, T7&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7) +{ + return Arguments7<T1&, T2&, T3&, T4&, T5&, T6&, T7&>(t1, t2, t3, t4, t5, t6, t7); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> struct Arguments8 : Arguments7<T1, T2, T3, T4, T5, T6, T7> { + typedef Arguments8<typename WTF::RemoveConst<typename WTF::RemoveReference<T1>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T2>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T3>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T4>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T5>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T6>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T7>::Type>::Type, + typename WTF::RemoveConst<typename WTF::RemoveReference<T8>::Type>::Type> ValueType; + + Arguments8() { } + + Arguments8(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + : Arguments7<T1, T2, T3, T4, T5, T6, T7>(t1, t2, t3, t4, t5, t6, t7) + , argument8(t8) + { + } + + void encode(ArgumentEncoder* encoder) const + { + Arguments7<T1, T2, T3, T4, T5, T6, T7>::encode(encoder); + encoder->encode(argument8); + } + + static bool decode(ArgumentDecoder* decoder, Arguments8& result) + { + if (!Arguments7<T1, T2, T3, T4, T5, T6, T7>::decode(decoder, result)) + return false; + + return decoder->decode(result.argument8); + } + + T8 argument8; +}; + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> Arguments8<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&, const T8&> In(const T1& t1, const T2& t2, const T3 &t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8) +{ + return Arguments8<const T1&, const T2&, const T3&, const T4&, const T5&, const T6&, const T7&, const T8&>(t1, t2, t3, t4, t5, t6, t7, t8); +} + +template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> Arguments8<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&> Out(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8) +{ + return Arguments8<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&>(t1, t2, t3, t4, t5, t6, t7, t8); +} + +} // namespace CoreIPC + +#endif // Arguments_h diff --git a/Source/WebKit2/Platform/CoreIPC/Attachment.cpp b/Source/WebKit2/Platform/CoreIPC/Attachment.cpp new file mode 100644 index 0000000..c8d35f4 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Attachment.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Attachment.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" + +namespace CoreIPC { + +Attachment::Attachment() + : m_type(Uninitialized) +{ +} + +#if PLATFORM(MAC) +Attachment::Attachment(mach_port_name_t port, mach_msg_type_name_t disposition) + : m_type(MachPortType) +{ + m_port.port = port; + m_port.disposition = disposition; +} + +Attachment::Attachment(void* address, mach_msg_size_t size, mach_msg_copy_options_t copyOptions, bool deallocate) + : m_type(MachOOLMemoryType) +{ + m_oolMemory.address = address; + m_oolMemory.size = size; + m_oolMemory.copyOptions = copyOptions; + m_oolMemory.deallocate = deallocate; +} + +void Attachment::release() +{ + m_type = Uninitialized; +} +#endif + +void Attachment::encode(ArgumentEncoder* encoder) const +{ + encoder->addAttachment(*this); +} + +bool Attachment::decode(ArgumentDecoder* decoder, Attachment& attachment) +{ + if (!decoder->removeAttachment(attachment)) + return false; + return true; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/Attachment.h b/Source/WebKit2/Platform/CoreIPC/Attachment.h new file mode 100644 index 0000000..55a09c9 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Attachment.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Attachment_h +#define Attachment_h + +namespace CoreIPC { + +class ArgumentDecoder; +class ArgumentEncoder; + +class Attachment { +public: + Attachment(); + + enum Type { + Uninitialized, +#if PLATFORM(MAC) + MachPortType, + MachOOLMemoryType +#endif + }; + +#if PLATFORM(MAC) + Attachment(mach_port_name_t port, mach_msg_type_name_t disposition); + Attachment(void* address, mach_msg_size_t size, mach_msg_copy_options_t copyOptions, bool deallocate); +#endif + + Type type() const { return m_type; } + +#if PLATFORM(MAC) + void release(); + + // MachPortType + mach_port_name_t port() const { ASSERT(m_type == MachPortType); return m_port.port; } + mach_msg_type_name_t disposition() const { ASSERT(m_type == MachPortType); return m_port.disposition; } + + // MachOOLMemoryType + void* address() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.address; } + mach_msg_size_t size() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.size; } + mach_msg_copy_options_t copyOptions() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.copyOptions; } + bool deallocate() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.deallocate; } +#endif + + void encode(ArgumentEncoder*) const; + static bool decode(ArgumentDecoder*, Attachment&); + +private: + Type m_type; + +#if PLATFORM(MAC) + union { + struct { + mach_port_name_t port; + mach_msg_type_name_t disposition; + } m_port; + struct { + void* address; + mach_msg_size_t size; + mach_msg_copy_options_t copyOptions; + bool deallocate; + } m_oolMemory; + }; +#endif +}; + +} // namespace CoreIPC + +#endif // Attachment_h diff --git a/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.cpp b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.cpp new file mode 100644 index 0000000..c975dff --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BinarySemaphore.h" + +namespace CoreIPC { + +BinarySemaphore::BinarySemaphore() + : m_isSet(false) +{ +} + +BinarySemaphore::~BinarySemaphore() +{ +} + +void BinarySemaphore::signal() +{ + MutexLocker locker(m_mutex); + + m_isSet = true; + m_condition.signal(); +} + +bool BinarySemaphore::wait(double absoluteTime) +{ + MutexLocker locker(m_mutex); + + bool timedOut = false; + while (!m_isSet) { + timedOut = !m_condition.timedWait(m_mutex, absoluteTime); + if (timedOut) + return false; + } + + // Reset the semaphore. + m_isSet = false; + return true; +} + + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.h b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.h new file mode 100644 index 0000000..8113236 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/BinarySemaphore.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BinarySemaphore_h +#define BinarySemaphore_h + +#include <wtf/Noncopyable.h> +#include <wtf/ThreadingPrimitives.h> + +namespace CoreIPC { + +class BinarySemaphore { + WTF_MAKE_NONCOPYABLE(BinarySemaphore); + +public: + BinarySemaphore(); + ~BinarySemaphore(); + + void signal(); + bool wait(double absoluteTime); + +private: + bool m_isSet; + + Mutex m_mutex; + ThreadCondition m_condition; +}; + +} // namespace CoreIPC + + +#endif // BinarySemaphore_h diff --git a/Source/WebKit2/Platform/CoreIPC/Connection.cpp b/Source/WebKit2/Platform/CoreIPC/Connection.cpp new file mode 100644 index 0000000..da92ce4 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Connection.cpp @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Connection.h" + +#include "CoreIPCMessageKinds.h" +#include "RunLoop.h" +#include "WorkItem.h" +#include <wtf/CurrentTime.h> + +using namespace std; + +namespace CoreIPC { + +PassRefPtr<Connection> Connection::createServerConnection(Identifier identifier, Client* client, RunLoop* clientRunLoop) +{ + return adoptRef(new Connection(identifier, true, client, clientRunLoop)); +} + +PassRefPtr<Connection> Connection::createClientConnection(Identifier identifier, Client* client, RunLoop* clientRunLoop) +{ + return adoptRef(new Connection(identifier, false, client, clientRunLoop)); +} + +Connection::Connection(Identifier identifier, bool isServer, Client* client, RunLoop* clientRunLoop) + : m_client(client) + , m_isServer(isServer) + , m_syncRequestID(0) + , m_isConnected(false) + , m_connectionQueue("com.apple.CoreIPC.ReceiveQueue") + , m_clientRunLoop(clientRunLoop) + , m_inDispatchMessageCount(0) + , m_didReceiveInvalidMessage(false) + , m_shouldWaitForSyncReplies(true) +{ + ASSERT(m_client); + + platformInitialize(identifier); +} + +Connection::~Connection() +{ + ASSERT(!isValid()); + + m_connectionQueue.invalidate(); +} + +void Connection::invalidate() +{ + if (!isValid()) { + // Someone already called invalidate(). + return; + } + + // Reset the client. + m_client = 0; + + m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::platformInvalidate)); +} + +void Connection::markCurrentlyDispatchedMessageAsInvalid() +{ + // This should only be called while processing a message. + ASSERT(m_inDispatchMessageCount > 0); + + m_didReceiveInvalidMessage = true; +} + +PassOwnPtr<ArgumentEncoder> Connection::createSyncMessageArgumentEncoder(uint64_t destinationID, uint64_t& syncRequestID) +{ + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + + // Encode the sync request ID. + syncRequestID = ++m_syncRequestID; + argumentEncoder->encode(syncRequestID); + + return argumentEncoder.release(); +} + +bool Connection::sendMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + if (!isValid()) + return false; + + MutexLocker locker(m_outgoingMessagesLock); + m_outgoingMessages.append(OutgoingMessage(messageID, arguments)); + + // FIXME: We should add a boolean flag so we don't call this when work has already been scheduled. + m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::sendOutgoingMessages)); + return true; +} + +bool Connection::sendSyncReply(PassOwnPtr<ArgumentEncoder> arguments) +{ + return sendMessage(MessageID(CoreIPCMessage::SyncMessageReply), arguments); +} + +PassOwnPtr<ArgumentDecoder> Connection::waitForMessage(MessageID messageID, uint64_t destinationID, double timeout) +{ + // First, check if this message is already in the incoming messages queue. + { + MutexLocker locker(m_incomingMessagesLock); + + for (size_t i = 0; i < m_incomingMessages.size(); ++i) { + const IncomingMessage& message = m_incomingMessages[i]; + + if (message.messageID() == messageID && message.arguments()->destinationID() == destinationID) { + OwnPtr<ArgumentDecoder> arguments(message.arguments()); + + // Erase the incoming message. + m_incomingMessages.remove(i); + return arguments.release(); + } + } + } + + double absoluteTime = currentTime() + timeout; + + std::pair<unsigned, uint64_t> messageAndDestination(std::make_pair(messageID.toInt(), destinationID)); + + { + MutexLocker locker(m_waitForMessageMutex); + + // We don't support having multiple clients wait for the same message. + ASSERT(!m_waitForMessageMap.contains(messageAndDestination)); + + // Insert our pending wait. + m_waitForMessageMap.set(messageAndDestination, 0); + } + + // Now wait for it to be set. + while (true) { + MutexLocker locker(m_waitForMessageMutex); + + HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*>::iterator it = m_waitForMessageMap.find(messageAndDestination); + if (it->second) { + OwnPtr<ArgumentDecoder> arguments(it->second); + m_waitForMessageMap.remove(it); + + return arguments.release(); + } + + // Now we wait. + if (!m_waitForMessageCondition.timedWait(m_waitForMessageMutex, absoluteTime)) { + // We timed out, now remove the pending wait. + m_waitForMessageMap.remove(messageAndDestination); + + break; + } + } + + return PassOwnPtr<ArgumentDecoder>(); +} + +PassOwnPtr<ArgumentDecoder> Connection::sendSyncMessage(MessageID messageID, uint64_t syncRequestID, PassOwnPtr<ArgumentEncoder> encoder, double timeout) +{ + // We only allow sending sync messages from the client run loop. + ASSERT(RunLoop::current() == m_clientRunLoop); + + if (!isValid()) + return 0; + + // Push the pending sync reply information on our stack. + { + MutexLocker locker(m_syncReplyStateMutex); + if (!m_shouldWaitForSyncReplies) + return 0; + + m_pendingSyncReplies.append(PendingSyncReply(syncRequestID)); + } + + // First send the message. + sendMessage(messageID, encoder); + + // Then wait for a reply. Waiting for a reply could involve dispatching incoming sync messages, so + // keep an extra reference to the connection here in case it's invalidated. + RefPtr<Connection> protect(this); + OwnPtr<ArgumentDecoder> reply = waitForSyncReply(syncRequestID, timeout); + + // Finally, pop the pending sync reply information. + { + MutexLocker locker(m_syncReplyStateMutex); + ASSERT(m_pendingSyncReplies.last().syncRequestID == syncRequestID); + m_pendingSyncReplies.removeLast(); + + if (m_pendingSyncReplies.isEmpty()) { + // This was the bottom-most sendSyncMessage call in the stack. If we have any pending incoming + // sync messages, they need to be dispatched. + if (!m_syncMessagesReceivedWhileWaitingForSyncReply.isEmpty()) { + // Add the messages. + MutexLocker locker(m_incomingMessagesLock); + m_incomingMessages.append(m_syncMessagesReceivedWhileWaitingForSyncReply); + m_syncMessagesReceivedWhileWaitingForSyncReply.clear(); + + // Schedule for the messages to be sent. + m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchMessages)); + } + } + } + + return reply.release(); +} + +PassOwnPtr<ArgumentDecoder> Connection::waitForSyncReply(uint64_t syncRequestID, double timeout) +{ + double absoluteTime = currentTime() + timeout; + + bool timedOut = false; + while (!timedOut) { + { + MutexLocker locker(m_syncReplyStateMutex); + + // First, check if we have any incoming sync messages that we need to process. + Vector<IncomingMessage> syncMessagesReceivedWhileWaitingForSyncReply; + m_syncMessagesReceivedWhileWaitingForSyncReply.swap(syncMessagesReceivedWhileWaitingForSyncReply); + + if (!syncMessagesReceivedWhileWaitingForSyncReply.isEmpty()) { + // Make sure to unlock the mutex here because we're calling out to client code which could in turn send + // another sync message and we don't want that to deadlock. + m_syncReplyStateMutex.unlock(); + + for (size_t i = 0; i < syncMessagesReceivedWhileWaitingForSyncReply.size(); ++i) { + IncomingMessage& message = syncMessagesReceivedWhileWaitingForSyncReply[i]; + OwnPtr<ArgumentDecoder> arguments = message.releaseArguments(); + + dispatchSyncMessage(message.messageID(), arguments.get()); + } + m_syncReplyStateMutex.lock(); + } + + // Second, check if there is a sync reply at the top of the stack. + ASSERT(!m_pendingSyncReplies.isEmpty()); + + PendingSyncReply& pendingSyncReply = m_pendingSyncReplies.last(); + ASSERT(pendingSyncReply.syncRequestID == syncRequestID); + + // We found the sync reply, or the connection was closed. + if (pendingSyncReply.didReceiveReply || !m_shouldWaitForSyncReplies) + return pendingSyncReply.releaseReplyDecoder(); + } + + // We didn't find a sync reply yet, keep waiting. + timedOut = !m_waitForSyncReplySemaphore.wait(absoluteTime); + } + + // We timed out. + return 0; +} + +void Connection::processIncomingMessage(MessageID messageID, PassOwnPtr<ArgumentDecoder> arguments) +{ + // Check if this is a sync reply. + if (messageID == MessageID(CoreIPCMessage::SyncMessageReply)) { + MutexLocker locker(m_syncReplyStateMutex); + ASSERT(!m_pendingSyncReplies.isEmpty()); + + PendingSyncReply& pendingSyncReply = m_pendingSyncReplies.last(); + ASSERT(pendingSyncReply.syncRequestID == arguments->destinationID()); + + pendingSyncReply.replyDecoder = arguments.leakPtr(); + pendingSyncReply.didReceiveReply = true; + + m_waitForSyncReplySemaphore.signal(); + return; + } + + // Check if this is a sync message. If it is, and we're waiting for a sync reply this message + // needs to be dispatched. If we don't we'll end up with a deadlock where both sync message senders are + // stuck waiting for a reply. + if (messageID.isSync()) { + MutexLocker locker(m_syncReplyStateMutex); + if (!m_pendingSyncReplies.isEmpty()) { + m_syncMessagesReceivedWhileWaitingForSyncReply.append(IncomingMessage(messageID, arguments)); + + // The message has been added, now wake up the client thread. + m_waitForSyncReplySemaphore.signal(); + return; + } + } + + // Check if we're waiting for this message. + { + MutexLocker locker(m_waitForMessageMutex); + + HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*>::iterator it = m_waitForMessageMap.find(std::make_pair(messageID.toInt(), arguments->destinationID())); + if (it != m_waitForMessageMap.end()) { + it->second = arguments.leakPtr(); + + m_waitForMessageCondition.signal(); + return; + } + } + + MutexLocker locker(m_incomingMessagesLock); + m_incomingMessages.append(IncomingMessage(messageID, arguments)); + + m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchMessages)); +} + +void Connection::connectionDidClose() +{ + // The connection is now invalid. + platformInvalidate(); + + { + MutexLocker locker(m_syncReplyStateMutex); + + ASSERT(m_shouldWaitForSyncReplies); + m_shouldWaitForSyncReplies = false; + + if (!m_pendingSyncReplies.isEmpty()) + m_waitForSyncReplySemaphore.signal(); + } + + m_client->didCloseOnConnectionWorkQueue(&m_connectionQueue, this); + + m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchConnectionDidClose)); +} + +void Connection::dispatchConnectionDidClose() +{ + // If the connection has been explicitly invalidated before dispatchConnectionDidClose was called, + // then the client will be null here. + if (!m_client) + return; + + + // Because we define a connection as being "valid" based on wheter it has a null client, we null out + // the client before calling didClose here. Otherwise, sendSync will try to send a message to the connection and + // will then wait indefinitely for a reply. + Client* client = m_client; + m_client = 0; + + client->didClose(this); +} + +bool Connection::canSendOutgoingMessages() const +{ + return m_isConnected && platformCanSendOutgoingMessages(); +} + +void Connection::sendOutgoingMessages() +{ + if (!canSendOutgoingMessages()) + return; + + while (true) { + OutgoingMessage message; + { + MutexLocker locker(m_outgoingMessagesLock); + if (m_outgoingMessages.isEmpty()) + break; + message = m_outgoingMessages.takeFirst(); + } + + if (!sendOutgoingMessage(message.messageID(), adoptPtr(message.arguments()))) + break; + } +} + +void Connection::dispatchSyncMessage(MessageID messageID, ArgumentDecoder* arguments) +{ + ASSERT(messageID.isSync()); + + // Decode the sync request ID. + uint64_t syncRequestID = 0; + + if (!arguments->decodeUInt64(syncRequestID) || !syncRequestID) { + // We received an invalid sync message. + arguments->markInvalid(); + return; + } + + // Create our reply encoder. + ArgumentEncoder* replyEncoder = ArgumentEncoder::create(syncRequestID).leakPtr(); + + // Hand off both the decoder and encoder to the client.. + SyncReplyMode syncReplyMode = m_client->didReceiveSyncMessage(this, messageID, arguments, replyEncoder); + + // FIXME: If the message was invalid, we should send back a SyncMessageError. + ASSERT(!arguments->isInvalid()); + + if (syncReplyMode == ManualReply) { + // The client will take ownership of the reply encoder and send it at some point in the future. + // We won't do anything here. + return; + } + + // Send the reply. + sendSyncReply(replyEncoder); +} + +void Connection::dispatchMessages() +{ + Vector<IncomingMessage> incomingMessages; + + { + MutexLocker locker(m_incomingMessagesLock); + m_incomingMessages.swap(incomingMessages); + } + + // Dispatch messages. + for (size_t i = 0; i < incomingMessages.size(); ++i) { + // If someone calls invalidate while we're invalidating messages, we should stop. + if (!m_client) + return; + + IncomingMessage& message = incomingMessages[i]; + OwnPtr<ArgumentDecoder> arguments = message.releaseArguments(); + + m_inDispatchMessageCount++; + + bool oldDidReceiveInvalidMessage = m_didReceiveInvalidMessage; + m_didReceiveInvalidMessage = false; + + if (message.messageID().isSync()) + dispatchSyncMessage(message.messageID(), arguments.get()); + else + m_client->didReceiveMessage(this, message.messageID(), arguments.get()); + + m_didReceiveInvalidMessage |= arguments->isInvalid(); + m_inDispatchMessageCount--; + + if (m_didReceiveInvalidMessage) + m_client->didReceiveInvalidMessage(this, message.messageID()); + + m_didReceiveInvalidMessage = oldDidReceiveInvalidMessage; + } +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/Connection.h b/Source/WebKit2/Platform/CoreIPC/Connection.h new file mode 100644 index 0000000..b7e5b0f --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/Connection.h @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Connection_h +#define Connection_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "Arguments.h" +#include "BinarySemaphore.h" +#include "MessageID.h" +#include "WorkQueue.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/OwnPtr.h> +#include <wtf/Threading.h> + +#if PLATFORM(MAC) +#include <mach/mach_port.h> +#elif PLATFORM(WIN) +#include <string> +#elif PLATFORM(QT) +#include <QString> +class QLocalServer; +class QLocalSocket; +#endif + +class RunLoop; + +namespace CoreIPC { + +class MessageID; + +enum SyncReplyMode { + AutomaticReply, + ManualReply +}; + +#define MESSAGE_CHECK_BASE(assertion, connection) do \ + if (!(assertion)) { \ + ASSERT(assertion); \ + (connection)->markCurrentlyDispatchedMessageAsInvalid(); \ + return; \ + } \ +while (0) + +class Connection : public ThreadSafeShared<Connection> { +public: + class MessageReceiver { + protected: + virtual ~MessageReceiver() { } + + public: + virtual void didReceiveMessage(Connection*, MessageID, ArgumentDecoder*) = 0; + virtual SyncReplyMode didReceiveSyncMessage(Connection*, MessageID, ArgumentDecoder*, ArgumentEncoder*) { ASSERT_NOT_REACHED(); return AutomaticReply; } + }; + + class Client : public MessageReceiver { + protected: + virtual ~Client() { } + + public: + virtual void didClose(Connection*) = 0; + virtual void didReceiveInvalidMessage(Connection*, MessageID) = 0; + + // Called on the connection work queue when the connection is closed, before + // didCall is called on the client thread. + virtual void didCloseOnConnectionWorkQueue(WorkQueue*, Connection*) { } + }; + +#if PLATFORM(MAC) + typedef mach_port_t Identifier; +#elif PLATFORM(WIN) + typedef HANDLE Identifier; + static bool createServerAndClientIdentifiers(Identifier& serverIdentifier, Identifier& clientIdentifier); +#elif PLATFORM(QT) + typedef const QString Identifier; +#elif PLATFORM(GTK) + typedef int Identifier; +#endif + + static PassRefPtr<Connection> createServerConnection(Identifier, Client*, RunLoop* clientRunLoop); + static PassRefPtr<Connection> createClientConnection(Identifier, Client*, RunLoop* clientRunLoop); + ~Connection(); + +#if PLATFORM(MAC) + void setShouldCloseConnectionOnMachExceptions(); +#endif + + bool open(); + void invalidate(); + void markCurrentlyDispatchedMessageAsInvalid(); + + // FIXME: This variant of send is deprecated, all clients should move to the overload that takes a message. + template<typename E, typename T> bool send(E messageID, uint64_t destinationID, const T& arguments); + + template<typename T> bool send(const T& message, uint64_t destinationID); + + static const unsigned long long NoTimeout = 10000000000ULL; + // FIXME: This variant of sendSync is deprecated, all clients should move to the overload that takes a message. + template<typename E, typename T, typename U> bool sendSync(E messageID, uint64_t destinationID, const T& arguments, const U& reply, double timeout = NoTimeout); + + template<typename T> bool sendSync(const T& message, const typename T::Reply& reply, uint64_t destinationID, double timeout = NoTimeout); + + template<typename E> PassOwnPtr<ArgumentDecoder> waitFor(E messageID, uint64_t destinationID, double timeout); + + PassOwnPtr<ArgumentEncoder> createSyncMessageArgumentEncoder(uint64_t destinationID, uint64_t& syncRequestID); + bool sendMessage(MessageID, PassOwnPtr<ArgumentEncoder>); + bool sendSyncReply(PassOwnPtr<ArgumentEncoder>); + +private: + template<typename T> class Message { + public: + Message() + : m_arguments(0) + { + } + + Message(MessageID messageID, PassOwnPtr<T> arguments) + : m_messageID(messageID) + , m_arguments(arguments.leakPtr()) + { + } + + MessageID messageID() const { return m_messageID; } + T* arguments() const { return m_arguments; } + + PassOwnPtr<T> releaseArguments() + { + T* arguments = m_arguments; + m_arguments = 0; + + return arguments; + } + + private: + MessageID m_messageID; + T* m_arguments; + }; + +public: + typedef Message<ArgumentEncoder> OutgoingMessage; + +private: + Connection(Identifier, bool isServer, Client*, RunLoop* clientRunLoop); + void platformInitialize(Identifier); + void platformInvalidate(); + + bool isValid() const { return m_client; } + + PassOwnPtr<ArgumentDecoder> waitForMessage(MessageID, uint64_t destinationID, double timeout); + + PassOwnPtr<ArgumentDecoder> sendSyncMessage(MessageID, uint64_t syncRequestID, PassOwnPtr<ArgumentEncoder>, double timeout); + PassOwnPtr<ArgumentDecoder> waitForSyncReply(uint64_t syncRequestID, double timeout); + + // Called on the connection work queue. + void processIncomingMessage(MessageID, PassOwnPtr<ArgumentDecoder>); + bool canSendOutgoingMessages() const; + bool platformCanSendOutgoingMessages() const; + void sendOutgoingMessages(); + bool sendOutgoingMessage(MessageID, PassOwnPtr<ArgumentEncoder>); + void connectionDidClose(); + + // Called on the listener thread. + void dispatchConnectionDidClose(); + void dispatchMessages(); + void dispatchSyncMessage(MessageID, ArgumentDecoder*); + + Client* m_client; + bool m_isServer; + uint64_t m_syncRequestID; + + bool m_isConnected; + WorkQueue m_connectionQueue; + RunLoop* m_clientRunLoop; + + uint32_t m_inDispatchMessageCount; + bool m_didReceiveInvalidMessage; + + // Incoming messages. + typedef Message<ArgumentDecoder> IncomingMessage; + + Mutex m_incomingMessagesLock; + Vector<IncomingMessage> m_incomingMessages; + + // Outgoing messages. + Mutex m_outgoingMessagesLock; + Deque<OutgoingMessage> m_outgoingMessages; + + ThreadCondition m_waitForMessageCondition; + Mutex m_waitForMessageMutex; + HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*> m_waitForMessageMap; + + // Represents a sync request for which we're waiting on a reply. + struct PendingSyncReply { + // The request ID. + uint64_t syncRequestID; + + // The reply decoder, will be null if there was an error processing the sync + // message on the other side. + ArgumentDecoder* replyDecoder; + + // Will be set to true once a reply has been received or an error occurred. + bool didReceiveReply; + + PendingSyncReply() + : syncRequestID(0) + , replyDecoder(0) + , didReceiveReply(false) + { + } + + explicit PendingSyncReply(uint64_t syncRequestID) + : syncRequestID(syncRequestID) + , replyDecoder(0) + , didReceiveReply(0) + { + } + + PassOwnPtr<ArgumentDecoder> releaseReplyDecoder() + { + OwnPtr<ArgumentDecoder> reply = adoptPtr(replyDecoder); + replyDecoder = 0; + + return reply.release(); + } + }; + + BinarySemaphore m_waitForSyncReplySemaphore; + + Mutex m_syncReplyStateMutex; + bool m_shouldWaitForSyncReplies; + Vector<PendingSyncReply> m_pendingSyncReplies; + Vector<IncomingMessage> m_syncMessagesReceivedWhileWaitingForSyncReply; + +#if PLATFORM(MAC) + // Called on the connection queue. + void receiveSourceEventHandler(); + void initializeDeadNameSource(); + void exceptionSourceEventHandler(); + + mach_port_t m_sendPort; + mach_port_t m_receivePort; + + // If setShouldCloseConnectionOnMachExceptions has been called, this has + // the exception port that exceptions from the other end will be sent on. + mach_port_t m_exceptionPort; + +#elif PLATFORM(WIN) + // Called on the connection queue. + void readEventHandler(); + void writeEventHandler(); + + Vector<uint8_t> m_readBuffer; + OVERLAPPED m_readState; + OwnPtr<ArgumentEncoder> m_pendingWriteArguments; + OVERLAPPED m_writeState; + HANDLE m_connectionPipe; +#elif PLATFORM(QT) + // Called on the connection queue. + void readyReadHandler(); + + Vector<uint8_t> m_readBuffer; + size_t m_currentMessageSize; + QLocalSocket* m_socket; + QString m_serverName; +#elif PLATFORM(GTK) + void readEventHandler(); + void processCompletedMessage(); + bool messageProcessingCompleted() { return !m_currentMessageSize; } + + int m_socket; + Vector<uint8_t> m_readBuffer; + size_t m_currentMessageSize; + size_t m_pendingBytes; +#endif +}; + +template<typename E, typename T> +bool Connection::send(E messageID, uint64_t destinationID, const T& arguments) +{ + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + argumentEncoder->encode(arguments); + + return sendMessage(MessageID(messageID), argumentEncoder.release()); +} + +template<typename T> bool Connection::send(const T& message, uint64_t destinationID) +{ + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + argumentEncoder->encode(message); + + return sendMessage(MessageID(T::messageID), argumentEncoder.release()); +} + +template<typename E, typename T, typename U> +inline bool Connection::sendSync(E messageID, uint64_t destinationID, const T& arguments, const U& reply, double timeout) +{ + uint64_t syncRequestID = 0; + OwnPtr<ArgumentEncoder> argumentEncoder = createSyncMessageArgumentEncoder(destinationID, syncRequestID); + + // Encode the input arguments. + argumentEncoder->encode(arguments); + + // Now send the message and wait for a reply. + OwnPtr<ArgumentDecoder> replyDecoder = sendSyncMessage(MessageID(messageID, MessageID::SyncMessage), syncRequestID, argumentEncoder.release(), timeout); + if (!replyDecoder) + return false; + + // Decode the reply. + return replyDecoder->decode(const_cast<U&>(reply)); +} + +template<typename T> bool Connection::sendSync(const T& message, const typename T::Reply& reply, uint64_t destinationID, double timeout) +{ + uint64_t syncRequestID = 0; + OwnPtr<ArgumentEncoder> argumentEncoder = createSyncMessageArgumentEncoder(destinationID, syncRequestID); + + // Encode the rest of the input arguments. + argumentEncoder->encode(message); + + // Now send the message and wait for a reply. + OwnPtr<ArgumentDecoder> replyDecoder = sendSyncMessage(MessageID(T::messageID, MessageID::SyncMessage), syncRequestID, argumentEncoder.release(), timeout); + if (!replyDecoder) + return false; + + // Decode the reply. + return replyDecoder->decode(const_cast<typename T::Reply&>(reply)); +} + +template<typename E> inline PassOwnPtr<ArgumentDecoder> Connection::waitFor(E messageID, uint64_t destinationID, double timeout) +{ + return waitForMessage(MessageID(messageID), destinationID, timeout); +} + +} // namespace CoreIPC + +#endif // Connection_h diff --git a/Source/WebKit2/Platform/CoreIPC/CoreIPCMessageKinds.h b/Source/WebKit2/Platform/CoreIPC/CoreIPCMessageKinds.h new file mode 100644 index 0000000..b2a2813 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/CoreIPCMessageKinds.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CoreIPCMessageKinds_h +#define CoreIPCMessageKinds_h + +#include "MessageID.h" + +namespace CoreIPC { + +namespace CoreIPCMessage { + +enum Kind { + InitializeConnection, + SyncMessageReply, +#if PLATFORM(MAC) + SetExceptionPort, +#endif +}; + +} // namespace CoreIPCMessage + +template<> struct MessageKindTraits<CoreIPCMessage::Kind> { + static const MessageClass messageClass = MessageClassCoreIPC; +}; + +} // namespace CoreIPC + +#endif // CoreIPCMessageKinds_h diff --git a/Source/WebKit2/Platform/CoreIPC/DataReference.cpp b/Source/WebKit2/Platform/CoreIPC/DataReference.cpp new file mode 100644 index 0000000..308fd6e --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/DataReference.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "DataReference.h" + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" + +namespace CoreIPC { + +void DataReference::encode(ArgumentEncoder* encoder) const +{ + encoder->encodeBytes(m_data, m_size); +} + +bool DataReference::decode(ArgumentDecoder* decoder, DataReference& dataReference) +{ + return decoder->decodeBytes(dataReference); +} + +} // namespace CoreIPC + + diff --git a/Source/WebKit2/Platform/CoreIPC/DataReference.h b/Source/WebKit2/Platform/CoreIPC/DataReference.h new file mode 100644 index 0000000..1657bea --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/DataReference.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DataReference_h +#define DataReference_h + +#include <inttypes.h> + +namespace CoreIPC { + +class ArgumentDecoder; +class ArgumentEncoder; + +class DataReference { +public: + DataReference() + : m_data(0) + , m_size(0) + { + } + + DataReference(const uint8_t* data, size_t size) + : m_data(data) + , m_size(size) + { + } + + bool isEmpty() const { return size() == 0; } + + size_t size() const { return m_size; } + const uint8_t* data() const + { + if (isEmpty()) + return 0; + return m_data; + } + + void encode(ArgumentEncoder* encoder) const; + static bool decode(ArgumentDecoder* decoder, DataReference& dataReference); + +private: + const uint8_t* m_data; + size_t m_size; +}; + +} // namespace CoreIPC + +#endif // DataReference_h diff --git a/Source/WebKit2/Platform/CoreIPC/HandleMessage.h b/Source/WebKit2/Platform/CoreIPC/HandleMessage.h new file mode 100644 index 0000000..534e825 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/HandleMessage.h @@ -0,0 +1,248 @@ +#ifndef HandleMessage_h +#define HandleMessage_h + +#include "Arguments.h" + +namespace CoreIPC { + +// Dispatch functions with no reply arguments. + +template<typename C, typename MF> +void callMemberFunction(const Arguments0&, C* object, MF function) +{ + (object->*function)(); +} + +template<typename C, typename MF, typename P1> +void callMemberFunction(const Arguments1<P1>& args, C* object, MF function) +{ + (object->*function)(args.argument1); +} + +template<typename C, typename MF, typename P1, typename P2> +void callMemberFunction(const Arguments2<P1, P2>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5> +void callMemberFunction(const Arguments5<P1, P2, P3, P4, P5>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> +void callMemberFunction(const Arguments6<P1, P2, P3, P4, P5, P6>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7> +void callMemberFunction(const Arguments7<P1, P2, P3, P4, P5, P6, P7>& args, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6, args.argument7); +} + +// Dispatch functions with reply arguments. + +template<typename C, typename MF> +void callMemberFunction(const Arguments0&, Arguments0&, C* object, MF function) +{ + (object->*function)(); +} + +template<typename C, typename MF, typename R1> +void callMemberFunction(const Arguments0&, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(replyArgs.argument1); +} + +template<typename C, typename MF, typename R1, typename R2> +void callMemberFunction(const Arguments0&, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1> +void callMemberFunction(const Arguments1<P1>& args, Arguments0&, C* object, MF function) +{ + (object->*function)(args.argument1); +} + +template<typename C, typename MF, typename P1, typename R1> +void callMemberFunction(const Arguments1<P1>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename R1, typename R2> +void callMemberFunction(const Arguments1<P1>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename R1, typename R2, typename R3> +void callMemberFunction(const Arguments1<P1>& args, Arguments3<R1, R2, R3>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3); +} + +template<typename C, typename MF, typename P1, typename P2> +void callMemberFunction(const Arguments2<P1, P2>& args, Arguments0&, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2); +} + +template<typename C, typename MF, typename P1, typename R1, typename R2, typename R3, typename R4> +void callMemberFunction(const Arguments1<P1>& args, Arguments4<R1, R2, R3, R4>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3, replyArgs.argument4); +} + +template<typename C, typename MF, typename P1, typename P2, typename R1> +void callMemberFunction(const Arguments2<P1, P2>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename R1, typename R2> +void callMemberFunction(const Arguments2<P1, P2>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename R1> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename R1, typename R2> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename R1> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename R1> +void callMemberFunction(const Arguments7<P1, P2, P3, P4, P5, P6, P7>& args, Arguments1<R1>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6, args.argument7, replyArgs.argument1); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename R1, typename R2> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, replyArgs.argument1, replyArgs.argument2); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename R1, typename R2> +void callMemberFunction(const Arguments5<P1, P2, P3, P4, P5>& args, Arguments2<R1, R2>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, replyArgs.argument1, replyArgs.argument2); +} + + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename R1, typename R2, typename R3> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, Arguments3<R1, R2, R3>& replyArgs, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3); +} + +// Variadic dispatch functions. + +template<typename C, typename MF> +void callMemberFunction(const Arguments0&, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(argumentDecoder); +} + +template<typename C, typename MF, typename P1> +void callMemberFunction(const Arguments1<P1>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2> +void callMemberFunction(const Arguments2<P1, P2>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3> +void callMemberFunction(const Arguments3<P1, P2, P3>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4> +void callMemberFunction(const Arguments4<P1, P2, P3, P4>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5> +void callMemberFunction(const Arguments5<P1, P2, P3, P4, P5>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, argumentDecoder); +} + +template<typename C, typename MF, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> +void callMemberFunction(const Arguments6<P1, P2, P3, P4, P5, P6>& args, ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + (object->*function)(args.argument1, args.argument2, args.argument3, args.argument4, args.argument5, args.argument6, argumentDecoder); +} + + +// Main dispatch functions + +template<typename T, typename C, typename MF> +void handleMessage(ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + typename T::DecodeType::ValueType arguments; + if (!argumentDecoder->decode(arguments)) + return; + callMemberFunction(arguments, object, function); +} + +template<typename T, typename C, typename MF> +void handleMessage(ArgumentDecoder* argumentDecoder, ArgumentEncoder* replyEncoder, C* object, MF function) +{ + typename T::DecodeType::ValueType arguments; + if (!argumentDecoder->decode(arguments)) + return; + + typename T::Reply::ValueType replyArguments; + callMemberFunction(arguments, replyArguments, object, function); + replyEncoder->encode(replyArguments); +} + +template<typename T, typename C, typename MF> +void handleMessageVariadic(ArgumentDecoder* argumentDecoder, C* object, MF function) +{ + typename T::DecodeType::ValueType arguments; + if (!argumentDecoder->decode(arguments)) + return; + callMemberFunction(arguments, argumentDecoder, object, function); +} + +} // namespace CoreIPC + +#endif // HandleMessage_h diff --git a/Source/WebKit2/Platform/CoreIPC/MessageID.h b/Source/WebKit2/Platform/CoreIPC/MessageID.h new file mode 100644 index 0000000..724302c --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/MessageID.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MessageID_h +#define MessageID_h + +namespace CoreIPC { + +enum MessageClass { + MessageClassReserved = 0, + + // Messages sent by Core IPC. + MessageClassCoreIPC, + + // Messages sent by the UI process to the web process. + MessageClassAuthenticationManager, + MessageClassDrawingArea, + MessageClassDrawingAreaLegacy, + MessageClassInjectedBundle, + MessageClassWebDatabaseManager, + MessageClassWebGeolocationManagerProxy, + MessageClassWebInspector, + MessageClassWebPage, + MessageClassWebProcess, + + // Messages sent by the web process to the UI process. + MessageClassDownloadProxy, + MessageClassDrawingAreaProxy, + MessageClassDrawingAreaProxyLegacy, + MessageClassWebContext, + MessageClassWebContextLegacy, + MessageClassWebDatabaseManagerProxy, + MessageClassWebGeolocationManager, + MessageClassWebInspectorProxy, + MessageClassWebPageProxy, + MessageClassWebProcessProxy, + MessageClassWebProcessProxyLegacy, + + // Messages sent by the UI process to the plug-in process. + MessageClassPluginProcess, + + // Messages sent by the plug-in process to the UI process. + MessageClassPluginProcessProxy, + + // Messages sent by the web process to the plug-in process. + MessageClassWebProcessConnection, + MessageClassPluginControllerProxy, + + // Messages sent by the plug-in process to the web process. + MessageClassPluginProxy, + + // NPObject messages sent by both the plug-in process and the web process. + MessageClassNPObjectMessageReceiver, +}; + +template<typename> struct MessageKindTraits { }; + + +/* + MessageID Layout (the most significant bit is reserved and therefore always zero) + + --------- + | Flags | 7 bits + |-------| + | Class | 8 bits + |-------| + | Msg | 16 bits + | Kind | + --------- +*/ + +class MessageID { +public: + enum Flags { + SyncMessage = 1 << 0, + }; + + MessageID() + : m_messageID(0) + { + } + + template <typename EnumType> + explicit MessageID(EnumType messageKind, unsigned char flags = 0) + : m_messageID(stripMostSignificantBit(flags << 24 | (MessageKindTraits<EnumType>::messageClass) << 16 | messageKind)) + { + } + + template <typename EnumType> + EnumType get() const + { + ASSERT(getClass() == MessageKindTraits<EnumType>::messageClass); + return static_cast<EnumType>(m_messageID & 0xffff); + } + + template <MessageClass K> + bool is() const + { + return getClass() == K; + } + + template <typename EnumType> + bool operator==(EnumType messageKind) const + { + return m_messageID == MessageID(messageKind).m_messageID; + } + + static MessageID fromInt(unsigned i) + { + MessageID messageID; + messageID.m_messageID = stripMostSignificantBit(i); + + return messageID; + } + + unsigned toInt() const { return m_messageID; } + + bool isSync() const { return getFlags() & SyncMessage; } + +private: + static inline unsigned stripMostSignificantBit(unsigned value) + { + return value & 0x7fffffff; + } + + unsigned char getFlags() const { return (m_messageID & 0xff000000) >> 24; } + unsigned char getClass() const { return (m_messageID & 0x00ff0000) >> 16; } + + unsigned m_messageID; +}; + +} // namespace CoreIPC + +#endif // MessageID_h diff --git a/Source/WebKit2/Platform/CoreIPC/MessageSender.h b/Source/WebKit2/Platform/CoreIPC/MessageSender.h new file mode 100644 index 0000000..e2ba0b5 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/MessageSender.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MessageSender_h +#define MessageSender_h + +#include <wtf/Assertions.h> +#include "Connection.h" + +namespace CoreIPC { + +template<typename T> class MessageSender { +public: + template<typename U> bool send(const U& message) + { + return send(message, static_cast<T*>(this)->destinationID()); + } + + template<typename U> bool send(const U& message, uint64_t destinationID) + { + OwnPtr<ArgumentEncoder> argumentEncoder = ArgumentEncoder::create(destinationID); + argumentEncoder->encode(message); + + return static_cast<T*>(this)->sendMessage(MessageID(U::messageID), argumentEncoder.release()); + } + + bool sendMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> argumentEncoder) + { + Connection* connection = static_cast<T*>(this)->connection(); + ASSERT(connection); + + return connection->sendMessage(messageID, argumentEncoder); + } + + template<typename U> bool sendSync(const U& message, const typename U::Reply& reply, double timeout = Connection::NoTimeout) + { + return sendSync(message, reply, static_cast<T*>(this)->destinationID(), timeout); + } + + template<typename U> bool sendSync(const U& message, const typename U::Reply& reply, uint64_t destinationID, double timeout = Connection::NoTimeout) + { + Connection* connection = static_cast<T*>(this)->connection(); + ASSERT(connection); + + return connection->sendSync(message, reply, destinationID, timeout); + } +}; + +} // namespace CoreIPC + +#endif // MessageSender_h diff --git a/Source/WebKit2/Platform/CoreIPC/gtk/ConnectionGtk.cpp b/Source/WebKit2/Platform/CoreIPC/gtk/ConnectionGtk.cpp new file mode 100644 index 0000000..65b1254 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/gtk/ConnectionGtk.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Connection.h" + +#include "ArgumentEncoder.h" +#include "WorkItem.h" +#include <errno.h> +#include <glib.h> +#include <sys/fcntl.h> + +using namespace std; + +namespace CoreIPC { + +static const size_t initialMessageBufferSize = 4096; + +static int readBytesFromSocket(int fileDescriptor, uint8_t* ptr, size_t length) +{ + ASSERT(fileDescriptor > 0); + ASSERT(buffer); + ASSERT(length > 0); + + ssize_t numberOfBytesRead = 0; + size_t pendingBytesToRead = length; + uint8_t* buffer = ptr; + + while (pendingBytesToRead > 0) { + if ((numberOfBytesRead = read(fileDescriptor, buffer, pendingBytesToRead)) < 0) { + if (errno == EINTR) + numberOfBytesRead = 0; + else if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + else + return 0; + } else if (!numberOfBytesRead) + break; + + buffer += numberOfBytesRead; + pendingBytesToRead -= numberOfBytesRead; + } + + return (length - pendingBytesToRead); +} + +static bool writeBytesToSocket(int fileDescriptor, uint8_t* ptr, size_t length) +{ + ASSERT(fileDescriptor > 0); + ASSERT(buffer); + ASSERT(length > 0); + + ssize_t numberOfBytesWritten = 0; + size_t pendingBytesToWrite = length; + uint8_t* buffer = ptr; + + // Keep writing to the socket till the complete message has been written. + while (pendingBytesToWrite > 0) { + if ((numberOfBytesWritten = write(fileDescriptor, buffer, pendingBytesToWrite)) < 0) { + if (errno == EINTR) + numberOfBytesWritten = 0; + else + return false; + } + buffer += numberOfBytesWritten; + pendingBytesToWrite -= numberOfBytesWritten; + } + + // Write operation failed if complete message is not written. + return !pendingBytesToWrite; +} + +void Connection::platformInitialize(Identifier identifier) +{ + m_currentMessageSize = 0; + m_pendingBytes = 0; + m_readBuffer.resize(initialMessageBufferSize); + m_socket = identifier; + m_isConnected = true; +} + +void Connection::platformInvalidate() +{ + if (!m_isConnected) + return; + + m_connectionQueue.unregisterEventSourceHandler(m_socket); + if (m_socket > 0) { + close(m_socket); + m_socket = -1; + } + + m_isConnected = false; +} + +void Connection::processCompletedMessage() +{ + size_t realBufferSize = m_currentMessageSize - sizeof(MessageID); + unsigned messageID = *reinterpret_cast<unsigned*>(m_readBuffer.data() + realBufferSize); + + processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); + + // Prepare for the next message. + m_currentMessageSize = 0; + m_pendingBytes = 0; +} + +void Connection::readEventHandler() +{ + if (m_socket < 0) + return; + + // Handle any previously unprocessed message. + if (!messageProcessingCompleted()) { + if ((m_pendingBytes -= readBytesFromSocket(m_socket, (m_readBuffer.data() + (m_currentMessageSize - m_pendingBytes)), m_pendingBytes)) > 0) + return; + + // Message received completely. Process the message now. + processCompletedMessage(); + } + + // Prepare to read the next message. + uint8_t sizeBuffer[sizeof(size_t)]; + memset(sizeBuffer, 0, sizeof(size_t)); + + while (messageProcessingCompleted()) { + if (readBytesFromSocket(m_socket, sizeBuffer, sizeof(size_t))) + m_currentMessageSize = *reinterpret_cast<size_t*>(sizeBuffer); + + if (!m_currentMessageSize) + break; + + if (m_readBuffer.size() < m_currentMessageSize) + m_readBuffer.grow(m_currentMessageSize); + + m_pendingBytes = m_currentMessageSize - readBytesFromSocket(m_socket, m_readBuffer.data(), m_currentMessageSize); + if (m_pendingBytes > 0) // Message partially received. + break; + + // Message received completely. Process the message now. + processCompletedMessage(); + + memset(sizeBuffer, 0, sizeof(size_t)); + } +} + +bool Connection::open() +{ + int flags = fcntl(m_socket, F_GETFL, 0); + fcntl(m_socket, F_SETFL, flags | O_NONBLOCK); + + // Register callbacks for connection termination and input data on the WorkQueue. + m_connectionQueue.registerEventSourceHandler(m_socket, (G_IO_HUP | G_IO_ERR), WorkItem::create(this, &Connection::connectionDidClose)); + m_connectionQueue.registerEventSourceHandler(m_socket, G_IO_IN, WorkItem::create(this, &Connection::readEventHandler)); + return true; +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + return (m_socket > 0); +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + if (m_socket < 0) + return false; + + // We put the message ID last. + arguments->encodeUInt32(messageID.toInt()); + + size_t bufferSize = arguments->bufferSize(); + + // Send the message size first. + if (!writeBytesToSocket(m_socket, reinterpret_cast<uint8_t*>(&bufferSize), sizeof(size_t))) + return false; + + if (!writeBytesToSocket(m_socket, arguments->buffer(), arguments->bufferSize())) + return false; + + return true; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/mac/ConnectionMac.cpp b/Source/WebKit2/Platform/CoreIPC/mac/ConnectionMac.cpp new file mode 100644 index 0000000..5e7bbbc --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/mac/ConnectionMac.cpp @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Connection.h" + +#include "CoreIPCMessageKinds.h" +#include "MachPort.h" +#include "MachUtilities.h" +#include "RunLoop.h" +#include <mach/vm_map.h> + +using namespace std; + +namespace CoreIPC { + +static const size_t inlineMessageMaxSize = 4096; + +enum { + MessageBodyIsOOL = 1 << 31 +}; + +void Connection::platformInvalidate() +{ + if (!m_isConnected) + return; + + m_isConnected = false; + + ASSERT(m_sendPort); + ASSERT(m_receivePort); + + // Unregister our ports. + m_connectionQueue.unregisterMachPortEventHandler(m_sendPort); + m_sendPort = MACH_PORT_NULL; + + m_connectionQueue.unregisterMachPortEventHandler(m_receivePort); + m_receivePort = MACH_PORT_NULL; + + if (m_exceptionPort) { + m_connectionQueue.unregisterMachPortEventHandler(m_exceptionPort); + m_exceptionPort = MACH_PORT_NULL; + } +} + +void Connection::platformInitialize(Identifier identifier) +{ + m_exceptionPort = MACH_PORT_NULL; + + if (m_isServer) { + m_receivePort = identifier; + m_sendPort = MACH_PORT_NULL; + } else { + m_receivePort = MACH_PORT_NULL; + m_sendPort = identifier; + } +} + +bool Connection::open() +{ + if (m_isServer) { + ASSERT(m_receivePort); + ASSERT(!m_sendPort); + + } else { + ASSERT(!m_receivePort); + ASSERT(m_sendPort); + + // Create the receive port. + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort); + + m_isConnected = true; + + // Send the initialize message, which contains a send right for the server to use. + send(CoreIPCMessage::InitializeConnection, 0, MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND)); + + // Set the dead name handler for our send port. + initializeDeadNameSource(); + } + + // Change the message queue length for the receive port. + setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE); + + // Register the data available handler. + m_connectionQueue.registerMachPortEventHandler(m_receivePort, WorkQueue::MachPortDataAvailable, WorkItem::create(this, &Connection::receiveSourceEventHandler)); + + // If we have an exception port, register the data available handler and send over the port to the other end. + if (m_exceptionPort) { + m_connectionQueue.registerMachPortEventHandler(m_exceptionPort, WorkQueue::MachPortDataAvailable, WorkItem::create(this, &Connection::exceptionSourceEventHandler)); + + send(CoreIPCMessage::SetExceptionPort, 0, MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND)); + } + + return true; +} + +static inline size_t machMessageSize(size_t bodySize, size_t numberOfPortDescriptors = 0, size_t numberOfOOLMemoryDescriptors = 0) +{ + size_t size = sizeof(mach_msg_header_t) + bodySize; + if (numberOfPortDescriptors || numberOfOOLMemoryDescriptors) { + size += sizeof(mach_msg_body_t); + if (numberOfPortDescriptors) + size += (numberOfPortDescriptors * sizeof(mach_msg_port_descriptor_t)); + if (numberOfOOLMemoryDescriptors) + size += (numberOfOOLMemoryDescriptors * sizeof(mach_msg_ool_ports_descriptor_t)); + } + return round_msg(size); +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + return true; +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + Vector<Attachment> attachments = arguments->releaseAttachments(); + + size_t numberOfPortDescriptors = 0; + size_t numberOfOOLMemoryDescriptors = 0; + for (size_t i = 0; i < attachments.size(); ++i) { + Attachment::Type type = attachments[i].type(); + if (type == Attachment::MachPortType) + numberOfPortDescriptors++; + else if (type == Attachment::MachOOLMemoryType) + numberOfOOLMemoryDescriptors++; + } + + size_t messageSize = machMessageSize(arguments->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors); + char buffer[inlineMessageMaxSize]; + + bool messageBodyIsOOL = false; + if (messageSize > sizeof(buffer)) { + messageBodyIsOOL = true; + + attachments.append(Attachment(arguments->buffer(), arguments->bufferSize(), MACH_MSG_VIRTUAL_COPY, false)); + numberOfOOLMemoryDescriptors++; + messageSize = machMessageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors); + } + + bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors > 0); + + mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(&buffer); + header->msgh_bits = isComplex ? MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND | MACH_MSGH_BITS_COMPLEX, 0) : MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); + header->msgh_size = messageSize; + header->msgh_remote_port = m_sendPort; + header->msgh_local_port = MACH_PORT_NULL; + header->msgh_id = messageID.toInt(); + if (messageBodyIsOOL) + header->msgh_id |= MessageBodyIsOOL; + + uint8_t* messageData; + + if (isComplex) { + mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1); + body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors; + + uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1); + for (size_t i = 0; i < attachments.size(); ++i) { + Attachment attachment = attachments[i]; + + mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); + switch (attachment.type()) { + case Attachment::MachPortType: + descriptor->port.name = attachment.port(); + descriptor->port.disposition = attachment.disposition(); + descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR; + + descriptorData += sizeof(mach_msg_port_descriptor_t); + break; + case Attachment::MachOOLMemoryType: + descriptor->out_of_line.address = attachment.address(); + descriptor->out_of_line.size = attachment.size(); + descriptor->out_of_line.copy = attachment.copyOptions(); + descriptor->out_of_line.deallocate = attachment.deallocate(); + descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR; + + descriptorData += sizeof(mach_msg_ool_descriptor_t); + break; + default: + ASSERT_NOT_REACHED(); + } + } + + messageData = descriptorData; + } else + messageData = (uint8_t*)(header + 1); + + // Copy the data if it is not being sent out-of-line. + if (!messageBodyIsOOL) + memcpy(messageData, arguments->buffer(), arguments->bufferSize()); + + ASSERT(m_sendPort); + + // Send the message. + kern_return_t kr = mach_msg(header, MACH_SEND_MSG, messageSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + // FIXME: What should we do here? + } + + return true; +} + +void Connection::initializeDeadNameSource() +{ + m_connectionQueue.registerMachPortEventHandler(m_sendPort, WorkQueue::MachPortDeadNameNotification, WorkItem::create(this, &Connection::connectionDidClose)); +} + +static PassOwnPtr<ArgumentDecoder> createArgumentDecoder(mach_msg_header_t* header) +{ + if (!(header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) { + // We have a simple message. + size_t bodySize = header->msgh_size - sizeof(mach_msg_header_t); + uint8_t* body = reinterpret_cast<uint8_t*>(header + 1); + + return adoptPtr(new ArgumentDecoder(body, bodySize)); + } + + bool messageBodyIsOOL = header->msgh_id & MessageBodyIsOOL; + + mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1); + mach_msg_size_t numDescriptors = body->msgh_descriptor_count; + ASSERT(numDescriptors); + + // Build attachment list + Deque<Attachment> attachments; + uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1); + + // If the message body was sent out-of-line, don't treat the last descriptor + // as an attachment, since it is really the message body. + if (messageBodyIsOOL) + --numDescriptors; + + for (mach_msg_size_t i = 0; i < numDescriptors; ++i) { + mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); + + switch (descriptor->type.type) { + case MACH_MSG_PORT_DESCRIPTOR: + attachments.append(Attachment(descriptor->port.name, descriptor->port.disposition)); + descriptorData += sizeof(mach_msg_port_descriptor_t); + break; + case MACH_MSG_OOL_DESCRIPTOR: + attachments.append(Attachment(descriptor->out_of_line.address, descriptor->out_of_line.size, + descriptor->out_of_line.copy, descriptor->out_of_line.deallocate)); + descriptorData += sizeof(mach_msg_ool_descriptor_t); + break; + default: + ASSERT(false && "Unhandled descriptor type"); + } + } + + if (messageBodyIsOOL) { + mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData); + ASSERT(descriptor->type.type == MACH_MSG_OOL_DESCRIPTOR); + Attachment messageBodyAttachment(descriptor->out_of_line.address, descriptor->out_of_line.size, + descriptor->out_of_line.copy, descriptor->out_of_line.deallocate); + + uint8_t* messageBody = static_cast<uint8_t*>(messageBodyAttachment.address()); + size_t messageBodySize = messageBodyAttachment.size(); + + ArgumentDecoder* argumentDecoder; + + if (attachments.isEmpty()) + argumentDecoder = new ArgumentDecoder(messageBody, messageBodySize); + else + argumentDecoder = new ArgumentDecoder(messageBody, messageBodySize, attachments); + + vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(messageBodyAttachment.address()), messageBodyAttachment.size()); + + return adoptPtr(argumentDecoder); + } + + uint8_t* messageBody = descriptorData; + size_t messageBodySize = header->msgh_size - (descriptorData - reinterpret_cast<uint8_t*>(header)); + + return adoptPtr(new ArgumentDecoder(messageBody, messageBodySize, attachments)); +} + +// The receive buffer size should always include the maximum trailer size. +static const size_t receiveBufferSize = inlineMessageMaxSize + MAX_TRAILER_SIZE; +typedef Vector<char, receiveBufferSize> ReceiveBuffer; + +static mach_msg_header_t* readFromMachPort(mach_port_t machPort, ReceiveBuffer& buffer) +{ + buffer.resize(receiveBufferSize); + + mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer.data()); + kern_return_t kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL); + if (kr == MACH_RCV_TIMED_OUT) + return 0; + + if (kr == MACH_RCV_TOO_LARGE) { + // The message was too large, resize the buffer and try again. + buffer.resize(header->msgh_size + MAX_TRAILER_SIZE); + header = reinterpret_cast<mach_msg_header_t*>(buffer.data()); + + kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL); + ASSERT(kr != MACH_RCV_TOO_LARGE); + } + + if (kr != MACH_MSG_SUCCESS) { + ASSERT_NOT_REACHED(); + return 0; + } + + return header; +} + +void Connection::receiveSourceEventHandler() +{ + ReceiveBuffer buffer; + + mach_msg_header_t* header = readFromMachPort(m_receivePort, buffer); + if (!header) + return; + + MessageID messageID = MessageID::fromInt(header->msgh_id); + OwnPtr<ArgumentDecoder> arguments = createArgumentDecoder(header); + ASSERT(arguments); + + if (messageID == MessageID(CoreIPCMessage::InitializeConnection)) { + ASSERT(m_isServer); + ASSERT(!m_isConnected); + ASSERT(!m_sendPort); + + MachPort port; + if (!arguments->decode(port)) { + // FIXME: Disconnect. + return; + } + + m_sendPort = port.port(); + + // Set the dead name source if needed. + if (m_sendPort) + initializeDeadNameSource(); + + m_isConnected = true; + + // Send any pending outgoing messages. + sendOutgoingMessages(); + + return; + } + + if (messageID == MessageID(CoreIPCMessage::SetExceptionPort)) { + MachPort exceptionPort; + if (!arguments->decode(exceptionPort)) + return; + + setMachExceptionPort(exceptionPort.port()); + return; + } + + processIncomingMessage(messageID, arguments.release()); +} + +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, error %x", kr); + ASSERT_NOT_REACHED(); + } + + connectionDidClose(); +} + +void Connection::setShouldCloseConnectionOnMachExceptions() +{ + ASSERT(m_exceptionPort == MACH_PORT_NULL); + + if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_exceptionPort) != KERN_SUCCESS) + ASSERT_NOT_REACHED(); + + if (mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) + ASSERT_NOT_REACHED(); +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/mac/MachPort.h b/Source/WebKit2/Platform/CoreIPC/mac/MachPort.h new file mode 100644 index 0000000..ecce16e --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/mac/MachPort.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MachPort_h +#define MachPort_h + +#include "ArgumentDecoder.h" +#include "ArgumentEncoder.h" +#include "Attachment.h" + +namespace CoreIPC { + +class MachPort { +public: + MachPort() + : m_port(MACH_PORT_NULL) + , m_disposition(0) + { + } + + MachPort(mach_port_name_t port, mach_msg_type_name_t disposition) + : m_port(port) + , m_disposition(disposition) + { + } + + void encode(ArgumentEncoder* encoder) const + { + encoder->encode(Attachment(m_port, m_disposition)); + } + + static bool decode(ArgumentDecoder* decoder, MachPort& p) + { + Attachment attachment; + if (!decoder->decode(attachment)) + return false; + + p.m_port = attachment.port(); + p.m_disposition = attachment.disposition(); + return true; + } + + mach_port_name_t port() const { return m_port; } + mach_msg_type_name_t disposition() const { return m_disposition; } + +private: + mach_port_name_t m_port; + mach_msg_type_name_t m_disposition; +}; + +} // namespace CoreIPC + +#endif // MachPort_h diff --git a/Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp b/Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp new file mode 100644 index 0000000..c0736b8 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Connection.h" + +#include "ArgumentEncoder.h" +#include "ProcessLauncher.h" +#include "WorkItem.h" +#include <QApplication> +#include <QLocalServer> +#include <QLocalSocket> + +using namespace std; + +namespace CoreIPC { + +// This is what other ports use... +static const size_t messageMaxSize = 4096; + +void Connection::platformInitialize(Identifier identifier) +{ + m_serverName = identifier; + m_socket = 0; + m_readBuffer.resize(messageMaxSize); + m_currentMessageSize = 0; +} + +void Connection::platformInvalidate() +{ + m_socket->disconnect(); + if (!m_isServer) + m_socket->deleteLater(); + m_socket = 0; +} + +void Connection::readyReadHandler() +{ + while (m_socket->bytesAvailable()) { + if (!m_currentMessageSize) { + size_t numberOfBytesRead = m_socket->read(reinterpret_cast<char*>(m_readBuffer.data()), sizeof(size_t)); + ASSERT_UNUSED(numberOfBytesRead, numberOfBytesRead); + m_currentMessageSize = *reinterpret_cast<size_t*>(m_readBuffer.data()); + } + + if (m_socket->bytesAvailable() < m_currentMessageSize) + return; + + if (m_readBuffer.size() < m_currentMessageSize) + m_readBuffer.grow(m_currentMessageSize); + + size_t numberOfBytesRead = m_socket->read(reinterpret_cast<char*>(m_readBuffer.data()), m_currentMessageSize); + ASSERT_UNUSED(numberOfBytesRead, numberOfBytesRead); + + // The messageID is encoded at the end of the buffer. + size_t realBufferSize = m_currentMessageSize - sizeof(uint32_t); + uint32_t messageID = *reinterpret_cast<uint32_t*>(m_readBuffer.data() + realBufferSize); + + processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); + + m_currentMessageSize = 0; + } +} + +bool Connection::open() +{ + ASSERT(!m_socket); + + if (m_isServer) { + m_socket = WebKit::ProcessLauncher::takePendingConnection(); + m_isConnected = m_socket; + if (m_isConnected) { + m_connectionQueue.moveSocketToWorkThread(m_socket); + m_connectionQueue.connectSignal(m_socket, SIGNAL(readyRead()), WorkItem::create(this, &Connection::readyReadHandler)); + } + } else { + m_socket = new QLocalSocket(); + m_socket->connectToServer(m_serverName); + m_connectionQueue.moveSocketToWorkThread(m_socket); + m_connectionQueue.connectSignal(m_socket, SIGNAL(readyRead()), WorkItem::create(this, &Connection::readyReadHandler)); + m_connectionQueue.connectSignal(m_socket, SIGNAL(disconnected()), WorkItem::create(this, &Connection::connectionDidClose)); + m_isConnected = m_socket->waitForConnected(); + } + return m_isConnected; +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + return m_socket; +} + +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; +} + +} // namespace CoreIPC diff --git a/Source/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp b/Source/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp new file mode 100644 index 0000000..695da78 --- /dev/null +++ b/Source/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Connection.h" + +#include "ArgumentEncoder.h" +#include "WorkItem.h" +#include <wtf/RandomNumber.h> +#include <wtf/text/WTFString.h> + +using namespace std; +// We explicitly don't use the WebCore namespace here because CoreIPC should only use WTF types and +// WTF::String is really in WTF. +using WTF::String; + +namespace CoreIPC { + +// FIXME: Rename this or use a different constant on windows. +static const size_t inlineMessageMaxSize = 4096; + +bool Connection::createServerAndClientIdentifiers(HANDLE& serverIdentifier, HANDLE& clientIdentifier) +{ + String pipeName; + + while (true) { + unsigned uniqueID = randomNumber() * std::numeric_limits<unsigned>::max(); + pipeName = String::format("\\\\.\\pipe\\com.apple.WebKit.%x", uniqueID); + + serverIdentifier = ::CreateNamedPipe(pipeName.charactersWithNullTermination(), + PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, inlineMessageMaxSize, inlineMessageMaxSize, + 0, 0); + if (!serverIdentifier && ::GetLastError() == ERROR_PIPE_BUSY) { + // There was already a pipe with this name, try again. + continue; + } + + break; + } + + if (!serverIdentifier) + return false; + + clientIdentifier = ::CreateFileW(pipeName.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (!clientIdentifier) { + ::CloseHandle(serverIdentifier); + return false; + } + + DWORD mode = PIPE_READMODE_MESSAGE; + if (!::SetNamedPipeHandleState(clientIdentifier, &mode, 0, 0)) { + ::CloseHandle(serverIdentifier); + ::CloseHandle(clientIdentifier); + return false; + } + + return true; +} + +void Connection::platformInitialize(Identifier identifier) +{ + memset(&m_readState, 0, sizeof(m_readState)); + m_readState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); + + memset(&m_writeState, 0, sizeof(m_writeState)); + m_writeState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); + + m_connectionPipe = identifier; + + // We connected the two ends of the pipe in createServerAndClientIdentifiers. + m_isConnected = true; +} + +void Connection::platformInvalidate() +{ + if (m_connectionPipe == INVALID_HANDLE_VALUE) + return; + + m_connectionQueue.unregisterAndCloseHandle(m_readState.hEvent); + m_readState.hEvent = 0; + + m_connectionQueue.unregisterAndCloseHandle(m_writeState.hEvent); + m_writeState.hEvent = 0; + + ::CloseHandle(m_connectionPipe); + m_connectionPipe = INVALID_HANDLE_VALUE; +} + +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); + + processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); + } + + // 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(); + } +} + +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; + } + ASSERT_NOT_REACHED(); + } + + // The pending write has finished, so we are now done with its arguments. Clearing this member + // will allow us to send messages again. + m_pendingWriteArguments = 0; + + // Now that the pending write has finished, we can try to send a new message. + sendOutgoingMessages(); +} + +bool Connection::open() +{ + // Start listening for read and write state events. + m_connectionQueue.registerHandle(m_readState.hEvent, WorkItem::create(this, &Connection::readEventHandler)); + m_connectionQueue.registerHandle(m_writeState.hEvent, WorkItem::create(this, &Connection::writeEventHandler)); + + // Schedule a read. + m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::readEventHandler)); + + return true; +} + +bool Connection::platformCanSendOutgoingMessages() const +{ + // We only allow sending one asynchronous message at a time. If we wanted to send more than one + // at once, we'd have to use multiple OVERLAPPED structures and hold onto multiple pending + // ArgumentEncoders (one of each for each simultaneous asynchronous message). + return !m_pendingWriteArguments; +} + +bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) +{ + ASSERT(!m_pendingWriteArguments); + + // Just bail if the handle has been closed. + if (m_connectionPipe == INVALID_HANDLE_VALUE) + return false; + + // We put the message ID last. + arguments->encodeUInt32(messageID.toInt()); + + // Write the outgoing message. + + if (::WriteFile(m_connectionPipe, arguments->buffer(), arguments->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 arguments so that they won't be destroyed + // before the write completes. + m_pendingWriteArguments = arguments; + + // We can only send one asynchronous message at a time (see comment in platformCanSendOutgoingMessages). + return false; +} + +} // namespace CoreIPC |