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