Created
February 5, 2014 11:59
-
-
Save Amanieu/8822209 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/common/IPC.h b/src/common/IPC.h | |
index c3dbc5c..38778a1 100644 | |
--- a/src/common/IPC.h | |
+++ b/src/common/IPC.h | |
@@ -46,9 +46,86 @@ Maryland 20850 USA. | |
#include "../engine/qcommon/q_shared.h" | |
#include "../engine/qcommon/qcommon.h" | |
+namespace IPC { | |
+ | |
+// Maximum number of bytes that can be sent in a message | |
+static const size_t MSG_MAX_BYTES = 128 << 10; | |
+ | |
+// Maximum number of handles that can be sent in a message | |
+static const size_t MSG_MAX_HANDLES = 8; | |
+ | |
+// Operating system handle type | |
+#ifdef _WIN32 | |
+// HANDLE is defined as void* in windows.h | |
+typedef void* OSHandleType; | |
+static const OSHandleType INVALID_HANDLE = NULL; | |
+#else | |
+typedef int OSHandleType; | |
+static const OSHandleType INVALID_HANDLE = -1; | |
+#endif | |
+ | |
+// IPC descriptor which can be sent over a socket. You should treat this as an | |
+// opaque type and not access any of the fields directly. | |
+#ifdef __native_client__ | |
+typedef int Desc; | |
+#else | |
+struct Desc { | |
+ OSHandleType handle; | |
+ int32_t type; | |
+ union { | |
+ uint64_t size; | |
+ int32_t flags; | |
+ }; | |
+}; | |
+#endif | |
+ | |
+// Conversion between Desc and handles | |
+enum FileOpenMode { | |
+ MODE_READ, | |
+ MODE_WRITE, | |
+ MODE_RW, | |
+ MODE_WRITE_APPEND, | |
+ MODE_RW_APPEND | |
+}; | |
+Desc DescFromFile(OSHandleType handle, FileOpenMode mode); | |
+OSHandleType DescToHandle(Desc desc); | |
+ | |
+class Socket { | |
+public: | |
+ Desc GetDesc() const; | |
+ static Socket FromDesc(Desc desc); | |
+ | |
+ bool SendMsg(const Writer& writer); | |
+ bool RecvMsg(Reader& reader); | |
+ | |
+ static bool CreatePair(Socket& a, Socket& b); | |
+ | |
+private: | |
+ OSHandleType handle; | |
+}; | |
+ | |
+class SharedMemory { | |
+public: | |
+ Desc GetDesc() const; | |
+ static SharedMemory FromDesc(Desc desc); | |
+ | |
+ static SharedMemory Create(size_t size); | |
+ | |
+ void* GetBase(); | |
+ size_t GetSize(); | |
+ | |
+private: | |
+ OSHandleType handle; | |
+ void* base; | |
+ size_t size; | |
+}; | |
+ | |
+// Base type for serialization traits. | |
+template<typename T, typename = void> struct SerializeTraits {}; | |
+ | |
class Writer { | |
public: | |
- void Write(const void* p, size_t len) | |
+ void WriteData(const void* p, size_t len) | |
{ | |
data.insert(data.end(), static_cast<const char*>(p), static_cast<const char*>(p) + len); | |
} | |
@@ -56,12 +133,15 @@ public: | |
{ | |
if (size > std::numeric_limits<uint32_t>::max()) | |
Com_Error(ERR_DROP, "Size out of range in IPC message"); | |
- uint32_t realSize = size; | |
- Write(&realSize, sizeof(uint32_t)); | |
+ Write<uint32_t>(size); | |
} | |
- void WriteHandle(NaCl::IPCHandle& h) | |
+ template<typename T, typename Arg> void Write(Arg&& value) | |
{ | |
- handles.push_back(&h); | |
+ SerializeTraits<T>::Write(*this, std::forward<Arg>(value)); | |
+ } | |
+ void WriteHandle(Desc h) | |
+ { | |
+ handles.push_back(h); | |
} | |
void Reset() | |
@@ -73,19 +153,19 @@ public: | |
{ | |
return data; | |
} | |
- const std::vector<NaCl::IPCHandle*>& GetHandles() const | |
+ const std::vector<Desc>& GetHandles() const | |
{ | |
return handles; | |
} | |
private: | |
std::vector<char> data; | |
- std::vector<NaCl::IPCHandle*> handles; | |
+ std::vector<Desc> handles; | |
}; | |
class Reader { | |
public: | |
- void Read(void* p, size_t len) | |
+ void ReadData(void* p, size_t len) | |
{ | |
if (pos + len <= data.size()) { | |
memcpy(p, &data[pos], len); | |
@@ -96,8 +176,7 @@ public: | |
template<typename T> size_t ReadSize() | |
{ | |
// Check for multiplication overflows when reading a size | |
- uint32_t size; | |
- Read(&size, sizeof(uint32_t)); | |
+ uint32_t size = this->Read<uint32_t>(); | |
if (size > std::numeric_limits<uint32_t>::max() / sizeof(T)) | |
Com_Error(ERR_DROP, "Size out of range in IPC message"); | |
return size; | |
@@ -111,7 +190,11 @@ public: | |
} else | |
Com_Error(ERR_DROP, "IPC message too short"); | |
} | |
- NaCl::IPCHandle ReadHandle() | |
+ template<typename T> decltype(SerializeTraits<T>::Read(std::declval<Reader&>())) Read() | |
+ { | |
+ return SerializeTraits<T>::Read(*this); | |
+ } | |
+ Desc ReadHandle() | |
{ | |
if (handles_pos <= handles.size()) | |
return std::move(handles[handles_pos++]); | |
@@ -128,32 +211,29 @@ public: | |
{ | |
return data; | |
} | |
- std::vector<NaCl::IPCHandle>& GetHandles() | |
+ std::vector<Desc>& GetHandles() | |
{ | |
return handles; | |
} | |
private: | |
std::vector<char> data; | |
- std::vector<NaCl::IPCHandle> handles; | |
+ std::vector<Desc> handles; | |
size_t pos; | |
size_t handles_pos; | |
}; | |
-// Base type for serialization traits. | |
-template<typename T, typename = void> struct SerializeTraits {}; | |
- | |
// Simple implementation for POD types | |
template<typename T> | |
struct SerializeTraits<T, typename std::enable_if<std::is_pod<T>::value>::type> { | |
static void Write(Writer& stream, const T& value) | |
{ | |
- stream.Write(std::addressof(value), sizeof(value)); | |
+ stream.WriteData(std::addressof(value), sizeof(value)); | |
} | |
static T Read(Reader& stream) | |
{ | |
T value; | |
- stream.Read(std::addressof(value), sizeof(value)); | |
+ stream.ReadData(std::addressof(value), sizeof(value)); | |
return value; | |
} | |
}; | |
@@ -164,13 +244,13 @@ struct SerializeTraits<std::vector<T>, typename std::enable_if<std::is_pod<T>::v | |
static void Write(Writer& stream, const std::vector<T>& value) | |
{ | |
stream.WriteSize(value.size()); | |
- stream.Write(value.data(), value.size() * sizeof(T)); | |
+ stream.WriteData(value.data(), value.size() * sizeof(T)); | |
} | |
static std::vector<T> Read(Reader& stream) | |
{ | |
std::vector<T> value; | |
value.resize(stream.ReadSize<T>()); | |
- stream.Read(value.data(), value.size() * sizeof(T)); | |
+ stream.ReadData(value.data(), value.size() * sizeof(T)); | |
return value; | |
} | |
}; | |
@@ -197,7 +277,7 @@ template<> struct SerializeTraits<std::string> { | |
static void Write(Writer& stream, Str::StringRef value) | |
{ | |
stream.WriteSize(value.size()); | |
- stream.Write(value.data(), value.size()); | |
+ stream.WriteData(value.data(), value.size()); | |
} | |
static Str::StringRef Read(Reader& stream) | |
{ | |
@@ -211,8 +291,6 @@ template<> struct SerializeTraits<std::string> { | |
// IPC message, which automatically serializes and deserializes objects | |
template<uint32_t Major, uint32_t Minor, typename... T> class Message { | |
- typedef std::tuple<T...> TupleType; | |
- | |
template<size_t Index, typename Tuple> static void FillTuple(Tuple&, Reader&) {} | |
template<size_t Index, typename Type0, typename... Types, typename Tuple> static void FillTuple(Tuple& tuple, Reader& stream) | |
{ | |
@@ -223,7 +301,7 @@ template<uint32_t Major, uint32_t Minor, typename... T> class Message { | |
template<size_t Index> static void SerializeImpl(Writer&) {} | |
template<size_t Index, typename Arg0, typename... Args> void SerializeImpl(Arg0&& arg0, Args&&... args) | |
{ | |
- SerializeTraits<typename std::tuple_element<Index, TupleType>::type>::Write(stream, std::forward<Arg0>(arg0)); | |
+ SerializeTraits<typename std::tuple_element<Index, std::tuple<T...>>::type>::Write(stream, std::forward<Arg0>(arg0)); | |
SerializeImpl<Index + 1>(std::forward<Args>(args)...); | |
} | |
@@ -249,4 +327,6 @@ public: | |
} | |
}; | |
+} // namespace IPC | |
+ | |
#endif // COMMON_IPC_H_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment