Squashed 'third_party/ntcore_2016/' content from commit d8de5e4

Change-Id: Id4839f41b6a620d8bae58dcf1710016671cc4992
git-subtree-dir: third_party/ntcore_2016
git-subtree-split: d8de5e4f19e612e7102172c0dbf152ce82d3d63a
diff --git a/src/Message.cpp b/src/Message.cpp
new file mode 100644
index 0000000..161d303
--- /dev/null
+++ b/src/Message.cpp
@@ -0,0 +1,303 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "Message.h"
+
+#include "Log.h"
+#include "WireDecoder.h"
+#include "WireEncoder.h"
+
+#define kClearAllMagic 0xD06CB27Aul
+
+using namespace nt;
+
+std::shared_ptr<Message> Message::Read(WireDecoder& decoder,
+                                       GetEntryTypeFunc get_entry_type) {
+  unsigned int msg_type;
+  if (!decoder.Read8(&msg_type)) return nullptr;
+  auto msg =
+      std::make_shared<Message>(static_cast<MsgType>(msg_type), private_init());
+  switch (msg_type) {
+    case kKeepAlive:
+      break;
+    case kClientHello: {
+      unsigned int proto_rev;
+      if (!decoder.Read16(&proto_rev)) return nullptr;
+      msg->m_id = proto_rev;
+      // This intentionally uses the provided proto_rev instead of
+      // decoder.proto_rev().
+      if (proto_rev >= 0x0300u) {
+        if (!decoder.ReadString(&msg->m_str)) return nullptr;
+      }
+      break;
+    }
+    case kProtoUnsup: {
+      if (!decoder.Read16(&msg->m_id)) return nullptr;  // proto rev
+      break;
+    }
+    case kServerHelloDone:
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received SERVER_HELLO_DONE in protocol < 3.0");
+        return nullptr;
+      }
+      break;
+    case kServerHello:
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received SERVER_HELLO_DONE in protocol < 3.0");
+        return nullptr;
+      }
+      if (!decoder.Read8(&msg->m_flags)) return nullptr;
+      if (!decoder.ReadString(&msg->m_str)) return nullptr;
+      break;
+    case kClientHelloDone:
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received CLIENT_HELLO_DONE in protocol < 3.0");
+        return nullptr;
+      }
+      break;
+    case kEntryAssign: {
+      if (!decoder.ReadString(&msg->m_str)) return nullptr;
+      NT_Type type;
+      if (!decoder.ReadType(&type)) return nullptr;  // name
+      if (!decoder.Read16(&msg->m_id)) return nullptr;  // id
+      if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr;  // seq num
+      if (decoder.proto_rev() >= 0x0300u) {
+        if (!decoder.Read8(&msg->m_flags)) return nullptr;  // flags
+      }
+      msg->m_value = decoder.ReadValue(type);
+      if (!msg->m_value) return nullptr;
+      break;
+    }
+    case kEntryUpdate: {
+      if (!decoder.Read16(&msg->m_id)) return nullptr;  // id
+      if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr;  // seq num
+      NT_Type type;
+      if (decoder.proto_rev() >= 0x0300u) {
+        if (!decoder.ReadType(&type)) return nullptr;
+      } else {
+        type = get_entry_type(msg->m_id);
+      }
+      DEBUG4("update message data type: " << type);
+      msg->m_value = decoder.ReadValue(type);
+      if (!msg->m_value) return nullptr;
+      break;
+    }
+    case kFlagsUpdate: {
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received FLAGS_UPDATE in protocol < 3.0");
+        return nullptr;
+      }
+      if (!decoder.Read16(&msg->m_id)) return nullptr;
+      if (!decoder.Read8(&msg->m_flags)) return nullptr;
+      break;
+    }
+    case kEntryDelete: {
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received ENTRY_DELETE in protocol < 3.0");
+        return nullptr;
+      }
+      if (!decoder.Read16(&msg->m_id)) return nullptr;
+      break;
+    }
+    case kClearEntries: {
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received CLEAR_ENTRIES in protocol < 3.0");
+        return nullptr;
+      }
+      unsigned long magic;
+      if (!decoder.Read32(&magic)) return nullptr;
+      if (magic != kClearAllMagic) {
+        decoder.set_error(
+            "received incorrect CLEAR_ENTRIES magic value, ignoring");
+        return nullptr;
+      }
+      break;
+    }
+    case kExecuteRpc: {
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received EXECUTE_RPC in protocol < 3.0");
+        return nullptr;
+      }
+      if (!decoder.Read16(&msg->m_id)) return nullptr;
+      if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr;  // uid
+      unsigned long size;
+      if (!decoder.ReadUleb128(&size)) return nullptr;
+      const char* params;
+      if (!decoder.Read(&params, size)) return nullptr;
+      msg->m_str = llvm::StringRef(params, size);
+      break;
+    }
+    case kRpcResponse: {
+      if (decoder.proto_rev() < 0x0300u) {
+        decoder.set_error("received RPC_RESPONSE in protocol < 3.0");
+        return nullptr;
+      }
+      if (!decoder.Read16(&msg->m_id)) return nullptr;
+      if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr;  // uid
+      unsigned long size;
+      if (!decoder.ReadUleb128(&size)) return nullptr;
+      const char* results;
+      if (!decoder.Read(&results, size)) return nullptr;
+      msg->m_str = llvm::StringRef(results, size);
+      break;
+    }
+    default:
+      decoder.set_error("unrecognized message type");
+      INFO("unrecognized message type: " << msg_type);
+      return nullptr;
+  }
+  return msg;
+}
+
+std::shared_ptr<Message> Message::ClientHello(llvm::StringRef self_id) {
+  auto msg = std::make_shared<Message>(kClientHello, private_init());
+  msg->m_str = self_id;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::ServerHello(unsigned int flags,
+                                              llvm::StringRef self_id) {
+  auto msg = std::make_shared<Message>(kServerHello, private_init());
+  msg->m_str = self_id;
+  msg->m_flags = flags;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::EntryAssign(llvm::StringRef name,
+                                              unsigned int id,
+                                              unsigned int seq_num,
+                                              std::shared_ptr<Value> value,
+                                              unsigned int flags) {
+  auto msg = std::make_shared<Message>(kEntryAssign, private_init());
+  msg->m_str = name;
+  msg->m_value = value;
+  msg->m_id = id;
+  msg->m_flags = flags;
+  msg->m_seq_num_uid = seq_num;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::EntryUpdate(unsigned int id,
+                                              unsigned int seq_num,
+                                              std::shared_ptr<Value> value) {
+  auto msg = std::make_shared<Message>(kEntryUpdate, private_init());
+  msg->m_value = value;
+  msg->m_id = id;
+  msg->m_seq_num_uid = seq_num;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::FlagsUpdate(unsigned int id,
+                                              unsigned int flags) {
+  auto msg = std::make_shared<Message>(kFlagsUpdate, private_init());
+  msg->m_id = id;
+  msg->m_flags = flags;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::EntryDelete(unsigned int id) {
+  auto msg = std::make_shared<Message>(kEntryDelete, private_init());
+  msg->m_id = id;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::ExecuteRpc(unsigned int id, unsigned int uid,
+                                             llvm::StringRef params) {
+  auto msg = std::make_shared<Message>(kExecuteRpc, private_init());
+  msg->m_str = params;
+  msg->m_id = id;
+  msg->m_seq_num_uid = uid;
+  return msg;
+}
+
+std::shared_ptr<Message> Message::RpcResponse(unsigned int id, unsigned int uid,
+                                              llvm::StringRef results) {
+  auto msg = std::make_shared<Message>(kRpcResponse, private_init());
+  msg->m_str = results;
+  msg->m_id = id;
+  msg->m_seq_num_uid = uid;
+  return msg;
+}
+
+void Message::Write(WireEncoder& encoder) const {
+  switch (m_type) {
+    case kKeepAlive:
+      encoder.Write8(kKeepAlive);
+      break;
+    case kClientHello:
+      encoder.Write8(kClientHello);
+      encoder.Write16(encoder.proto_rev());
+      if (encoder.proto_rev() < 0x0300u) return;
+      encoder.WriteString(m_str);
+      break;
+    case kProtoUnsup:
+      encoder.Write8(kProtoUnsup);
+      encoder.Write16(encoder.proto_rev());
+      break;
+    case kServerHelloDone:
+      encoder.Write8(kServerHelloDone);
+      break;
+    case kServerHello:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kServerHello);
+      encoder.Write8(m_flags);
+      encoder.WriteString(m_str);
+      break;
+    case kClientHelloDone:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kClientHelloDone);
+      break;
+    case kEntryAssign:
+      encoder.Write8(kEntryAssign);
+      encoder.WriteString(m_str);
+      encoder.WriteType(m_value->type());
+      encoder.Write16(m_id);
+      encoder.Write16(m_seq_num_uid);
+      if (encoder.proto_rev() >= 0x0300u) encoder.Write8(m_flags);
+      encoder.WriteValue(*m_value);
+      break;
+    case kEntryUpdate:
+      encoder.Write8(kEntryUpdate);
+      encoder.Write16(m_id);
+      encoder.Write16(m_seq_num_uid);
+      if (encoder.proto_rev() >= 0x0300u) encoder.WriteType(m_value->type());
+      encoder.WriteValue(*m_value);
+      break;
+    case kFlagsUpdate:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kFlagsUpdate);
+      encoder.Write16(m_id);
+      encoder.Write8(m_flags);
+      break;
+    case kEntryDelete:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kEntryDelete);
+      encoder.Write16(m_id);
+      break;
+    case kClearEntries:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kClearEntries);
+      encoder.Write32(kClearAllMagic);
+      break;
+    case kExecuteRpc:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kExecuteRpc);
+      encoder.Write16(m_id);
+      encoder.Write16(m_seq_num_uid);
+      encoder.WriteString(m_str);
+      break;
+    case kRpcResponse:
+      if (encoder.proto_rev() < 0x0300u) return;  // new message in version 3.0
+      encoder.Write8(kRpcResponse);
+      encoder.Write16(m_id);
+      encoder.Write16(m_seq_num_uid);
+      encoder.WriteString(m_str);
+      break;
+    default:
+      break;
+  }
+}