Brian Silverman | f7bd1c2 | 2015-12-24 16:07:11 -0800 | [diff] [blame^] | 1 | /*----------------------------------------------------------------------------*/ |
| 2 | /* Copyright (c) FIRST 2015. All Rights Reserved. */ |
| 3 | /* Open Source Software - may be modified and shared by FRC teams. The code */ |
| 4 | /* must be accompanied by the FIRST BSD license file in the root directory of */ |
| 5 | /* the project. */ |
| 6 | /*----------------------------------------------------------------------------*/ |
| 7 | |
| 8 | #include "Message.h" |
| 9 | |
| 10 | #include "Log.h" |
| 11 | #include "WireDecoder.h" |
| 12 | #include "WireEncoder.h" |
| 13 | |
| 14 | #define kClearAllMagic 0xD06CB27Aul |
| 15 | |
| 16 | using namespace nt; |
| 17 | |
| 18 | std::shared_ptr<Message> Message::Read(WireDecoder& decoder, |
| 19 | GetEntryTypeFunc get_entry_type) { |
| 20 | unsigned int msg_type; |
| 21 | if (!decoder.Read8(&msg_type)) return nullptr; |
| 22 | auto msg = |
| 23 | std::make_shared<Message>(static_cast<MsgType>(msg_type), private_init()); |
| 24 | switch (msg_type) { |
| 25 | case kKeepAlive: |
| 26 | break; |
| 27 | case kClientHello: { |
| 28 | unsigned int proto_rev; |
| 29 | if (!decoder.Read16(&proto_rev)) return nullptr; |
| 30 | msg->m_id = proto_rev; |
| 31 | // This intentionally uses the provided proto_rev instead of |
| 32 | // decoder.proto_rev(). |
| 33 | if (proto_rev >= 0x0300u) { |
| 34 | if (!decoder.ReadString(&msg->m_str)) return nullptr; |
| 35 | } |
| 36 | break; |
| 37 | } |
| 38 | case kProtoUnsup: { |
| 39 | if (!decoder.Read16(&msg->m_id)) return nullptr; // proto rev |
| 40 | break; |
| 41 | } |
| 42 | case kServerHelloDone: |
| 43 | if (decoder.proto_rev() < 0x0300u) { |
| 44 | decoder.set_error("received SERVER_HELLO_DONE in protocol < 3.0"); |
| 45 | return nullptr; |
| 46 | } |
| 47 | break; |
| 48 | case kServerHello: |
| 49 | if (decoder.proto_rev() < 0x0300u) { |
| 50 | decoder.set_error("received SERVER_HELLO_DONE in protocol < 3.0"); |
| 51 | return nullptr; |
| 52 | } |
| 53 | if (!decoder.Read8(&msg->m_flags)) return nullptr; |
| 54 | if (!decoder.ReadString(&msg->m_str)) return nullptr; |
| 55 | break; |
| 56 | case kClientHelloDone: |
| 57 | if (decoder.proto_rev() < 0x0300u) { |
| 58 | decoder.set_error("received CLIENT_HELLO_DONE in protocol < 3.0"); |
| 59 | return nullptr; |
| 60 | } |
| 61 | break; |
| 62 | case kEntryAssign: { |
| 63 | if (!decoder.ReadString(&msg->m_str)) return nullptr; |
| 64 | NT_Type type; |
| 65 | if (!decoder.ReadType(&type)) return nullptr; // name |
| 66 | if (!decoder.Read16(&msg->m_id)) return nullptr; // id |
| 67 | if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr; // seq num |
| 68 | if (decoder.proto_rev() >= 0x0300u) { |
| 69 | if (!decoder.Read8(&msg->m_flags)) return nullptr; // flags |
| 70 | } |
| 71 | msg->m_value = decoder.ReadValue(type); |
| 72 | if (!msg->m_value) return nullptr; |
| 73 | break; |
| 74 | } |
| 75 | case kEntryUpdate: { |
| 76 | if (!decoder.Read16(&msg->m_id)) return nullptr; // id |
| 77 | if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr; // seq num |
| 78 | NT_Type type; |
| 79 | if (decoder.proto_rev() >= 0x0300u) { |
| 80 | if (!decoder.ReadType(&type)) return nullptr; |
| 81 | } else { |
| 82 | type = get_entry_type(msg->m_id); |
| 83 | } |
| 84 | DEBUG4("update message data type: " << type); |
| 85 | msg->m_value = decoder.ReadValue(type); |
| 86 | if (!msg->m_value) return nullptr; |
| 87 | break; |
| 88 | } |
| 89 | case kFlagsUpdate: { |
| 90 | if (decoder.proto_rev() < 0x0300u) { |
| 91 | decoder.set_error("received FLAGS_UPDATE in protocol < 3.0"); |
| 92 | return nullptr; |
| 93 | } |
| 94 | if (!decoder.Read16(&msg->m_id)) return nullptr; |
| 95 | if (!decoder.Read8(&msg->m_flags)) return nullptr; |
| 96 | break; |
| 97 | } |
| 98 | case kEntryDelete: { |
| 99 | if (decoder.proto_rev() < 0x0300u) { |
| 100 | decoder.set_error("received ENTRY_DELETE in protocol < 3.0"); |
| 101 | return nullptr; |
| 102 | } |
| 103 | if (!decoder.Read16(&msg->m_id)) return nullptr; |
| 104 | break; |
| 105 | } |
| 106 | case kClearEntries: { |
| 107 | if (decoder.proto_rev() < 0x0300u) { |
| 108 | decoder.set_error("received CLEAR_ENTRIES in protocol < 3.0"); |
| 109 | return nullptr; |
| 110 | } |
| 111 | unsigned long magic; |
| 112 | if (!decoder.Read32(&magic)) return nullptr; |
| 113 | if (magic != kClearAllMagic) { |
| 114 | decoder.set_error( |
| 115 | "received incorrect CLEAR_ENTRIES magic value, ignoring"); |
| 116 | return nullptr; |
| 117 | } |
| 118 | break; |
| 119 | } |
| 120 | case kExecuteRpc: { |
| 121 | if (decoder.proto_rev() < 0x0300u) { |
| 122 | decoder.set_error("received EXECUTE_RPC in protocol < 3.0"); |
| 123 | return nullptr; |
| 124 | } |
| 125 | if (!decoder.Read16(&msg->m_id)) return nullptr; |
| 126 | if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr; // uid |
| 127 | unsigned long size; |
| 128 | if (!decoder.ReadUleb128(&size)) return nullptr; |
| 129 | const char* params; |
| 130 | if (!decoder.Read(¶ms, size)) return nullptr; |
| 131 | msg->m_str = llvm::StringRef(params, size); |
| 132 | break; |
| 133 | } |
| 134 | case kRpcResponse: { |
| 135 | if (decoder.proto_rev() < 0x0300u) { |
| 136 | decoder.set_error("received RPC_RESPONSE in protocol < 3.0"); |
| 137 | return nullptr; |
| 138 | } |
| 139 | if (!decoder.Read16(&msg->m_id)) return nullptr; |
| 140 | if (!decoder.Read16(&msg->m_seq_num_uid)) return nullptr; // uid |
| 141 | unsigned long size; |
| 142 | if (!decoder.ReadUleb128(&size)) return nullptr; |
| 143 | const char* results; |
| 144 | if (!decoder.Read(&results, size)) return nullptr; |
| 145 | msg->m_str = llvm::StringRef(results, size); |
| 146 | break; |
| 147 | } |
| 148 | default: |
| 149 | decoder.set_error("unrecognized message type"); |
| 150 | INFO("unrecognized message type: " << msg_type); |
| 151 | return nullptr; |
| 152 | } |
| 153 | return msg; |
| 154 | } |
| 155 | |
| 156 | std::shared_ptr<Message> Message::ClientHello(llvm::StringRef self_id) { |
| 157 | auto msg = std::make_shared<Message>(kClientHello, private_init()); |
| 158 | msg->m_str = self_id; |
| 159 | return msg; |
| 160 | } |
| 161 | |
| 162 | std::shared_ptr<Message> Message::ServerHello(unsigned int flags, |
| 163 | llvm::StringRef self_id) { |
| 164 | auto msg = std::make_shared<Message>(kServerHello, private_init()); |
| 165 | msg->m_str = self_id; |
| 166 | msg->m_flags = flags; |
| 167 | return msg; |
| 168 | } |
| 169 | |
| 170 | std::shared_ptr<Message> Message::EntryAssign(llvm::StringRef name, |
| 171 | unsigned int id, |
| 172 | unsigned int seq_num, |
| 173 | std::shared_ptr<Value> value, |
| 174 | unsigned int flags) { |
| 175 | auto msg = std::make_shared<Message>(kEntryAssign, private_init()); |
| 176 | msg->m_str = name; |
| 177 | msg->m_value = value; |
| 178 | msg->m_id = id; |
| 179 | msg->m_flags = flags; |
| 180 | msg->m_seq_num_uid = seq_num; |
| 181 | return msg; |
| 182 | } |
| 183 | |
| 184 | std::shared_ptr<Message> Message::EntryUpdate(unsigned int id, |
| 185 | unsigned int seq_num, |
| 186 | std::shared_ptr<Value> value) { |
| 187 | auto msg = std::make_shared<Message>(kEntryUpdate, private_init()); |
| 188 | msg->m_value = value; |
| 189 | msg->m_id = id; |
| 190 | msg->m_seq_num_uid = seq_num; |
| 191 | return msg; |
| 192 | } |
| 193 | |
| 194 | std::shared_ptr<Message> Message::FlagsUpdate(unsigned int id, |
| 195 | unsigned int flags) { |
| 196 | auto msg = std::make_shared<Message>(kFlagsUpdate, private_init()); |
| 197 | msg->m_id = id; |
| 198 | msg->m_flags = flags; |
| 199 | return msg; |
| 200 | } |
| 201 | |
| 202 | std::shared_ptr<Message> Message::EntryDelete(unsigned int id) { |
| 203 | auto msg = std::make_shared<Message>(kEntryDelete, private_init()); |
| 204 | msg->m_id = id; |
| 205 | return msg; |
| 206 | } |
| 207 | |
| 208 | std::shared_ptr<Message> Message::ExecuteRpc(unsigned int id, unsigned int uid, |
| 209 | llvm::StringRef params) { |
| 210 | auto msg = std::make_shared<Message>(kExecuteRpc, private_init()); |
| 211 | msg->m_str = params; |
| 212 | msg->m_id = id; |
| 213 | msg->m_seq_num_uid = uid; |
| 214 | return msg; |
| 215 | } |
| 216 | |
| 217 | std::shared_ptr<Message> Message::RpcResponse(unsigned int id, unsigned int uid, |
| 218 | llvm::StringRef results) { |
| 219 | auto msg = std::make_shared<Message>(kRpcResponse, private_init()); |
| 220 | msg->m_str = results; |
| 221 | msg->m_id = id; |
| 222 | msg->m_seq_num_uid = uid; |
| 223 | return msg; |
| 224 | } |
| 225 | |
| 226 | void Message::Write(WireEncoder& encoder) const { |
| 227 | switch (m_type) { |
| 228 | case kKeepAlive: |
| 229 | encoder.Write8(kKeepAlive); |
| 230 | break; |
| 231 | case kClientHello: |
| 232 | encoder.Write8(kClientHello); |
| 233 | encoder.Write16(encoder.proto_rev()); |
| 234 | if (encoder.proto_rev() < 0x0300u) return; |
| 235 | encoder.WriteString(m_str); |
| 236 | break; |
| 237 | case kProtoUnsup: |
| 238 | encoder.Write8(kProtoUnsup); |
| 239 | encoder.Write16(encoder.proto_rev()); |
| 240 | break; |
| 241 | case kServerHelloDone: |
| 242 | encoder.Write8(kServerHelloDone); |
| 243 | break; |
| 244 | case kServerHello: |
| 245 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 246 | encoder.Write8(kServerHello); |
| 247 | encoder.Write8(m_flags); |
| 248 | encoder.WriteString(m_str); |
| 249 | break; |
| 250 | case kClientHelloDone: |
| 251 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 252 | encoder.Write8(kClientHelloDone); |
| 253 | break; |
| 254 | case kEntryAssign: |
| 255 | encoder.Write8(kEntryAssign); |
| 256 | encoder.WriteString(m_str); |
| 257 | encoder.WriteType(m_value->type()); |
| 258 | encoder.Write16(m_id); |
| 259 | encoder.Write16(m_seq_num_uid); |
| 260 | if (encoder.proto_rev() >= 0x0300u) encoder.Write8(m_flags); |
| 261 | encoder.WriteValue(*m_value); |
| 262 | break; |
| 263 | case kEntryUpdate: |
| 264 | encoder.Write8(kEntryUpdate); |
| 265 | encoder.Write16(m_id); |
| 266 | encoder.Write16(m_seq_num_uid); |
| 267 | if (encoder.proto_rev() >= 0x0300u) encoder.WriteType(m_value->type()); |
| 268 | encoder.WriteValue(*m_value); |
| 269 | break; |
| 270 | case kFlagsUpdate: |
| 271 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 272 | encoder.Write8(kFlagsUpdate); |
| 273 | encoder.Write16(m_id); |
| 274 | encoder.Write8(m_flags); |
| 275 | break; |
| 276 | case kEntryDelete: |
| 277 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 278 | encoder.Write8(kEntryDelete); |
| 279 | encoder.Write16(m_id); |
| 280 | break; |
| 281 | case kClearEntries: |
| 282 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 283 | encoder.Write8(kClearEntries); |
| 284 | encoder.Write32(kClearAllMagic); |
| 285 | break; |
| 286 | case kExecuteRpc: |
| 287 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 288 | encoder.Write8(kExecuteRpc); |
| 289 | encoder.Write16(m_id); |
| 290 | encoder.Write16(m_seq_num_uid); |
| 291 | encoder.WriteString(m_str); |
| 292 | break; |
| 293 | case kRpcResponse: |
| 294 | if (encoder.proto_rev() < 0x0300u) return; // new message in version 3.0 |
| 295 | encoder.Write8(kRpcResponse); |
| 296 | encoder.Write16(m_id); |
| 297 | encoder.Write16(m_seq_num_uid); |
| 298 | encoder.WriteString(m_str); |
| 299 | break; |
| 300 | default: |
| 301 | break; |
| 302 | } |
| 303 | } |