1 /* Copyright 2016, Ableton AG, Berlin. All rights reserved. 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 * If you would like to incorporate Link into a proprietary software application, 17 * please contact <link-devs@ableton.com>. 18 */ 19 20 #pragma once 21 22 #include <ableton/platforms/asio/AsioWrapper.hpp> 23 #if defined(LINK_PLATFORM_MACOSX) 24 #include <ableton/platforms/darwin/Darwin.hpp> 25 #elif defined(LINK_PLATFORM_LINUX) 26 #include <ableton/platforms/linux/Linux.hpp> 27 #endif 28 29 #include <chrono> 30 #include <cstdint> 31 #include <type_traits> 32 #include <utility> 33 #include <vector> 34 35 #if defined(LINK_PLATFORM_WINDOWS) 36 #include <WS2tcpip.h> 37 #include <WinSock2.h> 38 #include <Windows.h> 39 #endif 40 41 namespace ableton 42 { 43 namespace discovery 44 { 45 46 // Concept: NetworkByteStreamSerializable 47 // 48 // A type that can be encoded to a stream of bytes and decoded from a 49 // stream of bytes in network byte order. The following type is for 50 // documentation purposes only. 51 52 struct NetworkByteStreamSerializable 53 { 54 friend std::uint32_t sizeInByteStream(const NetworkByteStreamSerializable&); 55 56 // The byte stream pointed to by 'out' must have sufficient space to 57 // hold this object, as defined by sizeInByteStream. 58 template <typename It> 59 friend It toNetworkByteStream(const NetworkByteStreamSerializable&, It out); 60 }; 61 62 // Deserialization aspect of the concept. Outside of the demonstration 63 // type above because clients must specify the type 64 // explicitly. Default implementation just defers to a class static 65 // method on T. For types that can't provide such a method, specialize 66 // this template. 67 template <typename T> 68 struct Deserialize 69 { 70 // Throws std::runtime_exception if parsing the type from the given 71 // byte range fails. Returns a pair of the correctly parsed value 72 // and an iterator to the next byte to parse. 73 template <typename It> 74 static std::pair<T, It> fromNetworkByteStream(It begin, It end) 75 { 76 return T::fromNetworkByteStream(std::move(begin), std::move(end)); 77 } 78 }; 79 80 81 // Default size implementation. Works for primitive types. 82 83 template <typename T, 84 typename std::enable_if<std::is_fundamental<T>::value>::type* = nullptr> 85 std::uint32_t sizeInByteStream(T) 86 { 87 return sizeof(T); 88 } 89 90 namespace detail 91 { 92 93 // utilities for implementing concept for primitive types 94 95 template <typename T, typename It> 96 It copyToByteStream(T t, It out) 97 { 98 using namespace std; 99 return copy_n( 100 reinterpret_cast<typename iterator_traits<It>::pointer>(&t), sizeof(t), out); 101 } 102 103 template <typename T, typename It> 104 std::pair<T, It> copyFromByteStream(It begin, const It end) 105 { 106 using namespace std; 107 using ItDiff = typename iterator_traits<It>::difference_type; 108 109 if (distance(begin, end) < static_cast<ItDiff>(sizeof(T))) 110 { 111 throw range_error("Parsing type from byte stream failed"); 112 } 113 else 114 { 115 T t; 116 const auto n = sizeof(t); 117 copy_n(begin, n, reinterpret_cast<uint8_t*>(&t)); 118 return make_pair(t, begin + n); 119 } 120 } 121 122 } // namespace detail 123 124 125 // Model the concept for unsigned integral types 126 127 // uint8_t 128 template <typename It> 129 It toNetworkByteStream(const uint8_t byte, It out) 130 { 131 return detail::copyToByteStream(byte, std::move(out)); 132 } 133 134 template <> 135 struct Deserialize<uint8_t> 136 { 137 template <typename It> 138 static std::pair<uint8_t, It> fromNetworkByteStream(It begin, It end) 139 { 140 return detail::copyFromByteStream<uint8_t>(std::move(begin), std::move(end)); 141 } 142 }; 143 144 // uint16_t 145 template <typename It> 146 It toNetworkByteStream(uint16_t s, It out) 147 { 148 return detail::copyToByteStream(htons(s), std::move(out)); 149 } 150 151 template <> 152 struct Deserialize<uint16_t> 153 { 154 template <typename It> 155 static std::pair<uint16_t, It> fromNetworkByteStream(It begin, It end) 156 { 157 auto result = detail::copyFromByteStream<uint16_t>(std::move(begin), std::move(end)); 158 result.first = ntohs(result.first); 159 return result; 160 } 161 }; 162 163 // uint32_t 164 template <typename It> 165 It toNetworkByteStream(uint32_t l, It out) 166 { 167 return detail::copyToByteStream(htonl(l), std::move(out)); 168 } 169 170 template <> 171 struct Deserialize<uint32_t> 172 { 173 template <typename It> 174 static std::pair<uint32_t, It> fromNetworkByteStream(It begin, It end) 175 { 176 auto result = detail::copyFromByteStream<uint32_t>(std::move(begin), std::move(end)); 177 result.first = ntohl(result.first); 178 return result; 179 } 180 }; 181 182 // int32_t in terms of uint32_t 183 template <typename It> 184 It toNetworkByteStream(int32_t l, It out) 185 { 186 return toNetworkByteStream(reinterpret_cast<const uint32_t&>(l), std::move(out)); 187 } 188 189 template <> 190 struct Deserialize<int32_t> 191 { 192 template <typename It> 193 static std::pair<int32_t, It> fromNetworkByteStream(It begin, It end) 194 { 195 auto result = 196 Deserialize<uint32_t>::fromNetworkByteStream(std::move(begin), std::move(end)); 197 return std::make_pair(reinterpret_cast<const int32_t&>(result.first), result.second); 198 } 199 }; 200 201 // uint64_t 202 template <typename It> 203 It toNetworkByteStream(uint64_t ll, It out) 204 { 205 return detail::copyToByteStream(htonll(ll), std::move(out)); 206 } 207 208 template <> 209 struct Deserialize<uint64_t> 210 { 211 template <typename It> 212 static std::pair<uint64_t, It> fromNetworkByteStream(It begin, It end) 213 { 214 auto result = detail::copyFromByteStream<uint64_t>(std::move(begin), std::move(end)); 215 result.first = ntohll(result.first); 216 return result; 217 } 218 }; 219 220 // int64_t in terms of uint64_t 221 template <typename It> 222 It toNetworkByteStream(int64_t ll, It out) 223 { 224 return toNetworkByteStream(reinterpret_cast<const uint64_t&>(ll), std::move(out)); 225 } 226 227 template <> 228 struct Deserialize<int64_t> 229 { 230 template <typename It> 231 static std::pair<int64_t, It> fromNetworkByteStream(It begin, It end) 232 { 233 auto result = 234 Deserialize<uint64_t>::fromNetworkByteStream(std::move(begin), std::move(end)); 235 return std::make_pair(reinterpret_cast<const int64_t&>(result.first), result.second); 236 } 237 }; 238 239 // bool 240 inline std::uint32_t sizeInByteStream(bool) 241 { 242 return sizeof(uint8_t); 243 } 244 245 template <typename It> 246 It toNetworkByteStream(bool bl, It out) 247 { 248 return toNetworkByteStream(static_cast<uint8_t>(bl), std::move(out)); 249 } 250 251 template <> 252 struct Deserialize<bool> 253 { 254 template <typename It> 255 static std::pair<bool, It> fromNetworkByteStream(It begin, It end) 256 { 257 auto result = 258 Deserialize<uint8_t>::fromNetworkByteStream(std::move(begin), std::move(end)); 259 return std::make_pair(result.first != 0, result.second); 260 } 261 }; 262 263 // std::chrono::microseconds 264 inline std::uint32_t sizeInByteStream(const std::chrono::microseconds micros) 265 { 266 return sizeInByteStream(micros.count()); 267 } 268 269 template <typename It> 270 It toNetworkByteStream(const std::chrono::microseconds micros, It out) 271 { 272 static_assert(sizeof(int64_t) == sizeof(std::chrono::microseconds::rep), 273 "The size of microseconds::rep must matche the size of int64_t."); 274 return toNetworkByteStream(static_cast<int64_t>(micros.count()), std::move(out)); 275 } 276 277 template <> 278 struct Deserialize<std::chrono::microseconds> 279 { 280 template <typename It> 281 static std::pair<std::chrono::microseconds, It> fromNetworkByteStream(It begin, It end) 282 { 283 using namespace std; 284 auto result = Deserialize<int64_t>::fromNetworkByteStream(move(begin), move(end)); 285 return make_pair(chrono::microseconds{result.first}, result.second); 286 } 287 }; 288 289 namespace detail 290 { 291 292 // Generic serialize/deserialize utilities for containers 293 294 template <typename Container> 295 std::uint32_t containerSizeInByteStream(const Container& container) 296 { 297 std::uint32_t totalSize = 0; 298 for (const auto& val : container) 299 { 300 totalSize += sizeInByteStream(val); 301 } 302 return totalSize; 303 } 304 305 template <typename Container, typename It> 306 It containerToNetworkByteStream(const Container& container, It out) 307 { 308 for (const auto& val : container) 309 { 310 out = toNetworkByteStream(val, out); 311 } 312 return out; 313 } 314 315 template <typename T, typename BytesIt, typename InsertIt> 316 BytesIt deserializeContainer(BytesIt bytesBegin, 317 const BytesIt bytesEnd, 318 InsertIt contBegin, 319 const std::uint32_t maxElements) 320 { 321 using namespace std; 322 std::uint32_t numElements = 0; 323 while (bytesBegin < bytesEnd && numElements < maxElements) 324 { 325 T newVal; 326 tie(newVal, bytesBegin) = Deserialize<T>::fromNetworkByteStream(bytesBegin, bytesEnd); 327 *contBegin++ = newVal; 328 ++numElements; 329 } 330 return bytesBegin; 331 } 332 333 } // namespace detail 334 335 // Need specific overloads for each container type, but use above 336 // utilities for common implementation 337 338 // array 339 template <typename T, std::size_t Size> 340 std::uint32_t sizeInByteStream(const std::array<T, Size>& arr) 341 { 342 return detail::containerSizeInByteStream(arr); 343 } 344 345 template <typename T, std::size_t Size, typename It> 346 It toNetworkByteStream(const std::array<T, Size>& arr, It out) 347 { 348 return detail::containerToNetworkByteStream(arr, std::move(out)); 349 } 350 351 template <typename T, std::size_t Size> 352 struct Deserialize<std::array<T, Size>> 353 { 354 template <typename It> 355 static std::pair<std::array<T, Size>, It> fromNetworkByteStream(It begin, It end) 356 { 357 using namespace std; 358 array<T, Size> result{}; 359 auto resultIt = 360 detail::deserializeContainer<T>(move(begin), move(end), move(result.begin()), Size); 361 return make_pair(move(result), move(resultIt)); 362 } 363 }; 364 365 // vector 366 template <typename T, typename Alloc> 367 std::uint32_t sizeInByteStream(const std::vector<T, Alloc>& vec) 368 { 369 return sizeof(uint32_t) + detail::containerSizeInByteStream(vec); 370 } 371 372 template <typename T, typename Alloc, typename It> 373 It toNetworkByteStream(const std::vector<T, Alloc>& vec, It out) 374 { 375 out = toNetworkByteStream(static_cast<uint32_t>(vec.size()), out); 376 return detail::containerToNetworkByteStream(vec, std::move(out)); 377 } 378 379 template <typename T, typename Alloc> 380 struct Deserialize<std::vector<T, Alloc>> 381 { 382 template <typename It> 383 static std::pair<std::vector<T, Alloc>, It> fromNetworkByteStream( 384 It bytesBegin, It bytesEnd) 385 { 386 using namespace std; 387 auto result_size = 388 Deserialize<uint32_t>::fromNetworkByteStream(move(bytesBegin), bytesEnd); 389 vector<T, Alloc> result; 390 auto resultIt = detail::deserializeContainer<T>( 391 move(result_size.second), move(bytesEnd), back_inserter(result), result_size.first); 392 return make_pair(move(result), move(resultIt)); 393 } 394 }; 395 396 // 2-tuple 397 template <typename X, typename Y> 398 std::uint32_t sizeInByteStream(const std::tuple<X, Y>& tup) 399 { 400 return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup)); 401 } 402 403 template <typename X, typename Y, typename It> 404 It toNetworkByteStream(const std::tuple<X, Y>& tup, It out) 405 { 406 return toNetworkByteStream( 407 std::get<1>(tup), toNetworkByteStream(std::get<0>(tup), std::move(out))); 408 } 409 410 template <typename X, typename Y> 411 struct Deserialize<std::tuple<X, Y>> 412 { 413 template <typename It> 414 static std::pair<std::tuple<X, Y>, It> fromNetworkByteStream(It begin, It end) 415 { 416 using namespace std; 417 auto xres = Deserialize<X>::fromNetworkByteStream(begin, end); 418 auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end); 419 return make_pair(make_tuple(move(xres.first), move(yres.first)), move(yres.second)); 420 } 421 }; 422 423 // 3-tuple 424 template <typename X, typename Y, typename Z> 425 std::uint32_t sizeInByteStream(const std::tuple<X, Y, Z>& tup) 426 { 427 return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup)) 428 + sizeInByteStream(std::get<2>(tup)); 429 } 430 431 template <typename X, typename Y, typename Z, typename It> 432 It toNetworkByteStream(const std::tuple<X, Y, Z>& tup, It out) 433 { 434 return toNetworkByteStream( 435 std::get<2>(tup), toNetworkByteStream(std::get<1>(tup), 436 toNetworkByteStream(std::get<0>(tup), std::move(out)))); 437 } 438 439 template <typename X, typename Y, typename Z> 440 struct Deserialize<std::tuple<X, Y, Z>> 441 { 442 template <typename It> 443 static std::pair<std::tuple<X, Y, Z>, It> fromNetworkByteStream(It begin, It end) 444 { 445 using namespace std; 446 auto xres = Deserialize<X>::fromNetworkByteStream(begin, end); 447 auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end); 448 auto zres = Deserialize<Z>::fromNetworkByteStream(yres.second, end); 449 return make_pair(make_tuple(move(xres.first), move(yres.first), move(zres.first)), 450 move(zres.second)); 451 } 452 }; 453 454 } // namespace discovery 455 } // namespace ableton 456