mavtables  0.2.1
MAVLink router and firewall.
test_UnixUDPSocket.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <cstdint>
21 #include <cstring>
22 #include <system_error>
23 
24 #include <catch.hpp>
25 #include <errno.h>
26 #include <fakeit.hpp>
27 
28 #include "UnixSyscalls.hpp"
29 #include "UnixUDPSocket.hpp"
30 #include "utility.hpp"
31 
32 #include "common.hpp"
33 
34 
35 using namespace std::chrono_literals;
36 
37 
38 TEST_CASE("UnixUDPSocket's create and bind a UDP socket on construction and "
39  "closes the socket on destruction.", "[UnixUDPSocket]")
40 {
41  SECTION("Without a specific IP address (no errors).")
42  {
43  // Mock system calls.
44  fakeit::Mock<UnixSyscalls> mock_sys;
45  // Mock 'socket'.
46  fakeit::When(Method(mock_sys, socket)).Return(3);
47  // Mock 'bind'.
48  struct sockaddr_in address;
49  fakeit::When(Method(mock_sys, bind)).Do(
50  [&](auto fd, auto addr, auto addrlen)
51  {
52  (void)fd;
53  std::memcpy(&address, addr, addrlen);
54  return 0;
55  });
56  // Mock 'close'.
57  fakeit::When(Method(mock_sys, close)).Return(0);
58  {
59  // Construct socket.
60  UnixUDPSocket socket(14050, {}, 0, mock_unique(mock_sys));
61  fakeit::Verify(Method(mock_sys, socket).Matching(
62  [&](auto family, auto type, auto protocol)
63  {
64  return family == AF_INET && type == SOCK_DGRAM && protocol == 0;
65  })).Once();
66  fakeit::Verify(Method(mock_sys, bind).Matching(
67  [&](auto fd, auto addr, auto addrlen)
68  {
69  (void)addr;
70  return fd == 3 && addrlen == sizeof(address);
71  })).Once();
72  REQUIRE(address.sin_family == AF_INET);
73  REQUIRE(ntohs(address.sin_port) == 14050);
74  REQUIRE(ntohl(address.sin_addr.s_addr) == INADDR_ANY);
75 
76  for (size_t i = 0; i < sizeof(address.sin_zero); ++i)
77  {
78  REQUIRE(address.sin_zero[i] == '\0');
79  }
80 
81  fakeit::Verify(Method(mock_sys, close).Using(3)).Exactly(0);
82  }
83  fakeit::Verify(Method(mock_sys, close).Using(3)).Once();
84  }
85  SECTION("With a specific IP address (no errors).")
86  {
87  fakeit::Mock<UnixSyscalls> mock_sys;
88  fakeit::When(Method(mock_sys, socket)).Return(3);
89  struct sockaddr_in address;
90  fakeit::When(Method(mock_sys, bind)).Do(
91  [&](auto fd, auto addr, auto addrlen)
92  {
93  (void)fd;
94  std::memcpy(&address, addr, addrlen);
95  return 0;
96  });
97  fakeit::When(Method(mock_sys, close)).Return(0);
98  {
99  UnixUDPSocket socket(
100  14050, IPAddress(1234567890), 0, mock_unique(mock_sys));
101  fakeit::Verify(Method(mock_sys, socket).Matching(
102  [&](auto family, auto type, auto protocol)
103  {
104  return family == AF_INET && type == SOCK_DGRAM && protocol == 0;
105  })).Once();
106  fakeit::Verify(Method(mock_sys, bind).Matching(
107  [](auto fd, auto addr, auto addrlen)
108  {
109  (void)addr;
110  return fd == 3 && addrlen == sizeof(address);
111  })).Once();
112  REQUIRE(address.sin_family == AF_INET);
113  REQUIRE(ntohs(address.sin_port) == 14050);
114  REQUIRE(ntohl(address.sin_addr.s_addr) == 1234567890);
115 
116  for (size_t i = 0; i < sizeof(address.sin_zero); ++i)
117  {
118  REQUIRE(address.sin_zero[i] == '\0');
119  }
120 
121  fakeit::Verify(Method(mock_sys, close).Using(3)).Exactly(0);
122  }
123  fakeit::Verify(Method(mock_sys, close).Using(3)).Once();
124  }
125  SECTION("Emmits errors from 'socket' system call.")
126  {
127  fakeit::Mock<UnixSyscalls> mock_sys;
128  fakeit::When(Method(mock_sys, socket)).AlwaysReturn(-1);
129  std::array<int, 7> errors{{
130  EACCES,
131  EAFNOSUPPORT,
132  EINVAL,
133  EMFILE,
134  ENOBUFS,
135  ENOMEM,
136  EPROTONOSUPPORT
137  }};
138 
139  for (auto error : errors)
140  {
141  errno = error;
142  REQUIRE_THROWS_AS(
143  UnixUDPSocket(14050, {}, 0, mock_unique(mock_sys)),
144  std::system_error);
145  }
146  }
147  SECTION("Emmits errors from 'bind' system call.")
148  {
149  fakeit::Mock<UnixSyscalls> mock_sys;
150  fakeit::When(Method(mock_sys, socket)).AlwaysReturn(4);
151  fakeit::When(Method(mock_sys, bind)).AlwaysReturn(-1);
152  std::array<int, 13> errors{{
153  EACCES,
154  EADDRINUSE,
155  EBADF,
156  EINVAL,
157  ENOTSOCK,
158  EADDRNOTAVAIL,
159  EFAULT,
160  ELOOP,
161  ENAMETOOLONG,
162  ENOENT,
163  ENOMEM,
164  ENOTDIR,
165  EROFS
166  }};
167 
168  for (auto error : errors)
169  {
170  errno = error;
171  REQUIRE_THROWS_AS(
172  UnixUDPSocket(14050, {}, 0, mock_unique(mock_sys)),
173  std::system_error);
174  }
175  }
176 }
177 
178 
179 TEST_CASE("UnixUDPSocket's 'send' method sends data on the socket.",
180  "[UnixUDPSocket]")
181 {
182  // Mock system calls.
183  fakeit::Mock<UnixSyscalls> mock_sys;
184  // Mock 'socket'.
185  fakeit::When(Method(mock_sys, socket)).Return(3);
186  // Mock 'bind'.
187  fakeit::When(Method(mock_sys, bind)).Return(0);
188  // Mock 'close'.
189  fakeit::When(Method(mock_sys, close)).Return(0);
190  SECTION("Without error.")
191  {
192  UnixUDPSocket socket(14050, {}, 0, mock_unique(mock_sys));
193  // Mock 'sendto'
194  std::vector<uint8_t> sent;
195  struct sockaddr_in address;
196  fakeit::When(Method(mock_sys, sendto)).Do(
197  [&](auto fd, auto buf, auto len, auto flags,
198  auto addr, auto addrlen)
199  {
200  (void)fd;
201  (void)flags;
202  sent.resize(len);
203  std::memcpy(sent.data(), buf, len);
204  std::memcpy(&address, addr, addrlen);
205  return len;
206  });
207  // Test
208  std::vector<uint8_t> vec = {1, 3, 3, 7};
209  socket.send(vec, IPAddress(1234567890, 14050));
210  // Verify 'sendto'.
211  fakeit::Verify(Method(mock_sys, sendto).Matching(
212  [](auto fd, auto buf, auto len, auto flags,
213  auto addr, auto addrlen)
214  {
215  (void)buf;
216  (void)addr;
217  return fd == 3 && len == 4 && flags == 0 &&
218  addrlen == sizeof(address);
219  })).Once();
220  REQUIRE(sent == vec);
221  REQUIRE(address.sin_family == AF_INET);
222  REQUIRE(ntohs(address.sin_port) == 14050);
223  REQUIRE(ntohl(address.sin_addr.s_addr) == 1234567890);
224 
225  for (size_t i = 0; i < sizeof(address.sin_zero); ++i)
226  {
227  REQUIRE(address.sin_zero[i] == '\0');
228  }
229  }
230  SECTION("Bitrate limit prevents writing packets too fast.")
231  {
232  UnixUDPSocket socket(14050, {}, 128, mock_unique(mock_sys));
233  fakeit::Fake(Method(mock_sys, sendto));
234  std::vector<uint8_t> vec = {1, 3, 3, 7}; // 4*8/128 = 0.25 seconds
235  socket.send(vec, IPAddress(1234567890, 14050));
236  fakeit::Verify(Method(mock_sys, sendto)).Once();
237  auto tic = std::chrono::steady_clock::now();
238  socket.send(vec, IPAddress(1234567890, 14050));
239  auto toc = std::chrono::steady_clock::now();
240  REQUIRE(
241  std::chrono::duration_cast<std::chrono::milliseconds>(
242  toc - tic).count() >= 150);
243  REQUIRE(
244  std::chrono::duration_cast<std::chrono::milliseconds>(
245  toc - tic).count() <= 350);
246  fakeit::Verify(Method(mock_sys, sendto)).Exactly(2);
247  }
248  SECTION("Emmits errors from 'sendto' system call.")
249  {
250  UnixUDPSocket socket(14050, {}, 0, mock_unique(mock_sys));
251  fakeit::When(Method(mock_sys, sendto)).AlwaysReturn(-1);
252  std::array<int, 18> errors{{
253  EACCES,
254  EAGAIN,
255  EWOULDBLOCK,
256  EALREADY,
257  EBADF,
258  ECONNRESET,
259  EDESTADDRREQ,
260  EFAULT,
261  EINTR,
262  EINVAL,
263  EISCONN,
264  EMSGSIZE,
265  ENOBUFS,
266  ENOMEM,
267  ENOTCONN,
268  ENOTSOCK,
269  EOPNOTSUPP,
270  EPIPE
271  }};
272 
273  for (auto error : errors)
274  {
275  errno = error;
276  REQUIRE_THROWS_AS(
277  socket.send({1, 3, 3, 7}, IPAddress(1234567890, 14050)),
278  std::system_error);
279  }
280  }
281 }
282 
283 
284 TEST_CASE("UnixUDPSocket's 'receive' method receives data on the socket.",
285  "[UnixUDPSocket]")
286 {
287  // Mock system calls.
288  fakeit::Mock<UnixSyscalls> mock_sys;
289  // Mock 'socket'.
290  fakeit::When(Method(mock_sys, socket)).AlwaysReturn(3);
291  // Mock 'bind'.
292  fakeit::When(Method(mock_sys, bind)).AlwaysReturn(0);
293  // Mock 'close'.
294  fakeit::When(Method(mock_sys, close)).AlwaysReturn(0);
295  // Construct socket.
296  UnixUDPSocket socket(14050, {}, 0, mock_unique(mock_sys));
297  SECTION("Timeout, no packet (no errors).")
298  {
299  // Mock 'poll'.
300  struct pollfd fds;
301  fakeit::When(Method(mock_sys, poll)).Do(
302  [&](auto fds_, auto nfds, auto timeout)
303  {
304  (void)timeout;
305  std::memcpy(&fds, fds_, nfds * sizeof(fds));
306  return 0;
307  });
308  // Test.
309  REQUIRE(
310  socket.receive(250ms) ==
311  std::pair<std::vector<uint8_t>, IPAddress>({}, IPAddress(0)));
312  // Verify 'poll'.
313  fakeit::Verify(Method(mock_sys, poll).Matching(
314  [](auto fds_, auto nfds, auto timeout)
315  {
316  (void)fds_;
317  return nfds == 1 && timeout == 250;
318  })).Once();
319  REQUIRE(fds.fd == 3);
320  REQUIRE(fds.events == POLLIN);
321  REQUIRE(fds.revents == 0);
322  }
323  SECTION("Poll error, close and restart the socket (no other errors).")
324  {
325  // Mock 'bind'.
326  struct sockaddr_in address;
327  fakeit::When(Method(mock_sys, bind)).Do(
328  [&](auto fd, auto addr, auto addrlen)
329  {
330  (void)fd;
331  std::memcpy(&address, addr, addrlen);
332  return 0;
333  });
334  // Mock 'poll'.
335  struct pollfd fds;
336  fakeit::When(Method(mock_sys, poll)).Do(
337  [&](auto fds_, auto nfds, auto timeout)
338  {
339  (void)timeout;
340  std::memcpy(&fds, fds_, nfds * sizeof(fds));
341  fds_->revents = POLLERR;
342  return 1;
343  });
344  // Test
345  REQUIRE(
346  socket.receive(250ms) ==
347  std::pair<std::vector<uint8_t>, IPAddress>({}, IPAddress(0)));
348  // Verify 'poll'.
349  fakeit::Verify(Method(mock_sys, poll).Matching(
350  [](auto fds_, auto nfds, auto timeout)
351  {
352  (void)fds_;
353  return nfds == 1 && timeout == 250;
354  })).Once();
355  REQUIRE(fds.fd == 3);
356  REQUIRE(fds.events == POLLIN);
357  REQUIRE(fds.revents == 0);
358  // Verify 'socket'.
359  fakeit::Verify(Method(mock_sys, socket).Matching(
360  [&](auto family, auto type, auto protocol)
361  {
362  return family == AF_INET && type == SOCK_DGRAM && protocol == 0;
363  })).Exactly(2);
364  // Verify 'bind'.
365  fakeit::Verify(Method(mock_sys, bind).Matching(
366  [&](auto fd, auto addr, auto addrlen)
367  {
368  (void)addr;
369  return fd == 3 && addrlen == sizeof(address);
370  })).Exactly(2);
371  REQUIRE(address.sin_family == AF_INET);
372  REQUIRE(ntohs(address.sin_port) == 14050);
373  REQUIRE(ntohl(address.sin_addr.s_addr) == INADDR_ANY);
374 
375  for (size_t i = 0; i < sizeof(address.sin_zero); ++i)
376  {
377  REQUIRE(address.sin_zero[i] == '\0');
378  }
379 
380  // Verify 'close'.
381  fakeit::Verify(Method(mock_sys, close).Using(3)).Once();
382  }
383  SECTION("Packet available (no errors).")
384  {
385  // Mock 'poll'.
386  struct pollfd fds;
387  fakeit::When(Method(mock_sys, poll)).Do(
388  [&](auto fds_, auto nfds, auto timeout)
389  {
390  (void)timeout;
391  std::memcpy(&fds, fds_, nfds * sizeof(fds));
392  fds_->revents = POLLIN;
393  return 1;
394  });
395  // Mock 'ioctl'.
396  fakeit::When(Method(mock_sys, ioctl)).Do(
397  [](auto fd, auto request, auto size)
398  {
399  (void)fd;
400  (void)request;
401  *reinterpret_cast<int *>(size) = 4;
402  return 0;
403  });
404  // Mock 'recvfrom'.
405  socklen_t address_length = 0;
406  fakeit::When(Method(mock_sys, recvfrom)).Do(
407  [&](auto fd, auto buf, auto len, auto flags,
408  auto addr, auto addrlen)
409  {
410  (void)fd;
411  (void)flags;
412  // Write to buffer.
413  std::vector<uint8_t> vec = {1, 3, 3, 7};
414  std::memcpy(buf, vec.data(), std::min(vec.size(), len));
415  // Set address
416  struct sockaddr_in address;
417  address.sin_family = AF_INET;
418  address.sin_port = htons(static_cast<uint16_t>(5000));
419  address.sin_addr.s_addr = htonl(static_cast<uint32_t>(1234567890));
420  memset(address.sin_zero, '\0', sizeof(address.sin_zero));
421  std::memcpy(
422  addr, &address,
423  std::min(static_cast<size_t>(*addrlen), sizeof(address)));
424  address_length = *addrlen;
425  *addrlen = static_cast<socklen_t>(
426  std::min(static_cast<size_t>(*addrlen),
427  sizeof(address)));
428  // Return number of received bytes.
429  return std::min(vec.size(), len);
430  });
431  // Test
432  auto [data, ip] = socket.receive(250ms);
433  REQUIRE(data == std::vector<uint8_t>({1, 3, 3, 7}));
434  REQUIRE(ip == IPAddress(1234567890, 5000));
435  // Verify 'poll'.
436  fakeit::Verify(Method(mock_sys, poll).Matching(
437  [](auto fds_, auto nfds, auto timeout)
438  {
439  (void)fds_;
440  return nfds == 1 && timeout == 250;
441  })).Once();
442  REQUIRE(fds.fd == 3);
443  REQUIRE(fds.events == POLLIN);
444  REQUIRE(fds.revents == 0);
445  // Verify 'ioctl'.
446  fakeit::Verify(Method(mock_sys, ioctl).Matching(
447  [](auto fd, auto request, auto size)
448  {
449  (void)size;
450  return fd == 3 && request == FIONREAD;
451  })).Once();
452  // Verify 'recvfrom'.
453  fakeit::Verify(Method(mock_sys, recvfrom).Matching(
454  [](auto fd, auto buf, auto len, auto flags,
455  auto addr, auto addrlen)
456  {
457  (void)buf;
458  (void)addr;
459  (void)addrlen;
460  return fd == 3 && len >= 4 && flags == 0;
461  })).Once();
462  REQUIRE(address_length >= sizeof(sockaddr_in));
463  }
464  SECTION("Packet available (not IPv4).")
465  {
466  // Mock poll system call.
467  struct pollfd fds;
468  fakeit::When(Method(mock_sys, poll)).Do(
469  [&](auto fds_, auto nfds, auto timeout)
470  {
471  (void)timeout;
472  std::memcpy(&fds, fds_, nfds * sizeof(fds));
473  fds_->revents = POLLIN;
474  return 1;
475  });
476  // Mock ioctl system call.
477  fakeit::When(Method(mock_sys, ioctl)).Do(
478  [](auto fd, auto request, auto size)
479  {
480  (void)fd;
481  (void)request;
482  *reinterpret_cast<int *>(size) = 4;
483  return 0;
484  });
485  // Mock recvfrom.
486  socklen_t address_length = 0;
487  fakeit::When(Method(mock_sys, recvfrom)).Do(
488  [&](auto fd, auto buf, auto len, auto flags,
489  auto addr, auto addrlen)
490  {
491  (void)fd;
492  (void)flags;
493  // Write to buffer.
494  std::vector<uint8_t> vec = {1, 3, 3, 7};
495  std::memcpy(buf, vec.data(), std::min(vec.size(), len));
496  // Set address
497  struct sockaddr_in address;
498  address.sin_family = AF_INET6;
499  address.sin_port = htons(static_cast<uint16_t>(5000));
500  address.sin_addr.s_addr = htonl(static_cast<uint32_t>(1234567890));
501  memset(address.sin_zero, '\0', sizeof(address.sin_zero));
502  std::memcpy(
503  addr, &address,
504  std::min(static_cast<size_t>(*addrlen), sizeof(address)));
505  address_length = *addrlen;
506  *addrlen = static_cast<socklen_t>(
507  std::min(static_cast<size_t>(*addrlen),
508  sizeof(address)));
509  // Return number of received bytes.
510  return std::min(vec.size(), len);
511  });
512  // Test
513  auto [data, ip] = socket.receive(250ms);
514  REQUIRE(data == std::vector<uint8_t>());
515  REQUIRE(ip == IPAddress(0));
516  // Verify poll system call.
517  fakeit::Verify(Method(mock_sys, poll).Matching(
518  [](auto fds_, auto nfds, auto timeout)
519  {
520  (void)fds_;
521  return nfds == 1 && timeout == 250;
522  })).Once();
523  REQUIRE(fds.fd == 3);
524  REQUIRE(fds.events == POLLIN);
525  REQUIRE(fds.revents == 0);
526  // Verify ioctl system call.
527  fakeit::Verify(Method(mock_sys, ioctl).Matching(
528  [](auto fd, auto request, auto size)
529  {
530  (void)size;
531  return fd == 3 && request == FIONREAD;
532  })).Once();
533  // Verify recvfrom.
534  fakeit::Verify(Method(mock_sys, recvfrom).Matching(
535  [](auto fd, auto buf, auto len, auto flags,
536  auto addr, auto addrlen)
537  {
538  (void)buf;
539  (void)addr;
540  (void)addrlen;
541  return fd == 3 && len >= 4 && flags == 0;
542  })).Once();
543  REQUIRE(address_length >= sizeof(sockaddr_in));
544  }
545  SECTION("Packet available (IP address truncated).")
546  {
547  // Mock poll system call.
548  struct pollfd fds;
549  fakeit::When(Method(mock_sys, poll)).Do(
550  [&](auto fds_, auto nfds, auto timeout)
551  {
552  (void)timeout;
553  std::memcpy(&fds, fds_, nfds * sizeof(fds));
554  fds_->revents = POLLIN;
555  return 1;
556  });
557  // Mock ioctl system call.
558  fakeit::When(Method(mock_sys, ioctl)).Do(
559  [](auto fd, auto request, auto size)
560  {
561  (void)fd;
562  (void)request;
563  *reinterpret_cast<int *>(size) = 4;
564  return 0;
565  });
566  // Mock recvfrom.
567  socklen_t address_length = 0;
568  fakeit::When(Method(mock_sys, recvfrom)).Do(
569  [&](auto fd, auto buf, auto len, auto flags,
570  auto addr, auto addrlen)
571  {
572  (void)fd;
573  (void)flags;
574  // Write to buffer.
575  std::vector<uint8_t> vec = {1, 3, 3, 7};
576  std::memcpy(buf, vec.data(), std::min(vec.size(), len));
577  // Set address
578  struct sockaddr_in address;
579  address.sin_family = AF_INET;
580  address.sin_port = htons(static_cast<uint16_t>(5000));
581  address.sin_addr.s_addr = htonl(static_cast<uint32_t>(1234567890));
582  memset(address.sin_zero, '\0', sizeof(address.sin_zero));
583  std::memcpy(
584  addr, &address,
585  std::min(static_cast<size_t>(*addrlen), sizeof(address)));
586  address_length = *addrlen;
587  *addrlen = static_cast<socklen_t>(
588  std::min(static_cast<size_t>(*addrlen),
589  sizeof(address))) + 1;
590  // Return number of received bytes.
591  return std::min(vec.size(), len);
592  });
593  // Test
594  auto [data, ip] = socket.receive(250ms);
595  REQUIRE(data == std::vector<uint8_t>());
596  REQUIRE(ip == IPAddress(0));
597  // Verify poll system call.
598  fakeit::Verify(Method(mock_sys, poll).Matching(
599  [](auto fds_, auto nfds, auto timeout)
600  {
601  (void)fds_;
602  return nfds == 1 && timeout == 250;
603  })).Once();
604  REQUIRE(fds.fd == 3);
605  REQUIRE(fds.events == POLLIN);
606  REQUIRE(fds.revents == 0);
607  // Verify ioctl system call.
608  fakeit::Verify(Method(mock_sys, ioctl).Matching(
609  [](auto fd, auto request, auto size)
610  {
611  (void)size;
612  return fd == 3 && request == FIONREAD;
613  })).Once();
614  // Verify recvfrom.
615  fakeit::Verify(Method(mock_sys, recvfrom).Matching(
616  [](auto fd, auto buf, auto len, auto flags,
617  auto addr, auto addrlen)
618  {
619  (void)buf;
620  (void)addr;
621  (void)addrlen;
622  return fd == 3 && len >= 4 && flags == 0;
623  })).Once();
624  REQUIRE(address_length >= sizeof(sockaddr_in));
625  }
626  SECTION("Emmits errors from 'recvfrom' system call.")
627  {
628  // Mock poll system call.
629  struct pollfd fds;
630  fakeit::When(Method(mock_sys, poll)).AlwaysDo(
631  [&](auto fds_, auto nfds, auto timeout)
632  {
633  (void)timeout;
634  std::memcpy(&fds, fds_, nfds * sizeof(fds));
635  fds_->revents = POLLIN;
636  return 1;
637  });
638  // Mock ioctl system call.
639  fakeit::When(Method(mock_sys, ioctl)).AlwaysDo(
640  [](auto fd, auto request, auto size)
641  {
642  (void)fd;
643  (void)request;
644  *reinterpret_cast<int *>(size) = 4;
645  return 0;
646  });
647  // Mock recvfrom.
648  fakeit::When(Method(mock_sys, recvfrom)).AlwaysReturn(-1);
649  // Test
650  std::array<int, 13> errors{{
651  EACCES,
652  EWOULDBLOCK,
653  EBADF,
654  ECONNRESET,
655  EINTR,
656  EINVAL,
657  ENOTCONN,
658  ENOTSOCK,
659  EOPNOTSUPP,
660  ETIMEDOUT,
661  EIO,
662  ENOBUFS,
663  ENOMEM
664  }};
665 
666  for (auto error : errors)
667  {
668  errno = error;
669  REQUIRE_THROWS_AS(socket.receive(250ms), std::system_error);
670  }
671  }
672  SECTION("Emmits errors from 'ioctl' system call.")
673  {
674  // Mock poll system call.
675  struct pollfd fds;
676  fakeit::When(Method(mock_sys, poll)).AlwaysDo(
677  [&](auto fds_, auto nfds, auto timeout)
678  {
679  (void)timeout;
680  std::memcpy(&fds, fds_, nfds * sizeof(fds));
681  fds_->revents = POLLIN;
682  return 1;
683  });
684  // Mock ioctl system call.
685  fakeit::When(Method(mock_sys, ioctl)).AlwaysReturn(-1);
686  // Test
687  std::array<int, 4> errors{{
688  EBADF,
689  EFAULT,
690  EINVAL,
691  ENOTTY
692  }};
693 
694  for (auto error : errors)
695  {
696  errno = error;
697  REQUIRE_THROWS_AS(socket.receive(250ms), std::system_error);
698  }
699  }
700  SECTION("Emmits errors from 'poll' system call.")
701  {
702  // Mock poll system call.
703  fakeit::When(Method(mock_sys, poll)).AlwaysReturn(-1);
704  // Test
705  std::array<int, 4> errors{{
706  EFAULT,
707  EINTR,
708  EINVAL,
709  ENOMEM
710  }};
711 
712  for (auto error : errors)
713  {
714  errno = error;
715  REQUIRE_THROWS_AS(socket.receive(250ms), std::system_error);
716  }
717  }
718 }
719 
720 
721 TEST_CASE("UnixUDPSocket's are printable.", "[UnixUDPSocket]")
722 {
723  // Mock system calls.
724  fakeit::Mock<UnixSyscalls> mock_sys;
725  // Mock 'socket'.
726  fakeit::When(Method(mock_sys, socket)).Return(3);
727  // Mock 'bind'.
728  struct sockaddr_in address;
729  fakeit::When(Method(mock_sys, bind)).Do(
730  [&](auto fd, auto addr, auto addrlen)
731  {
732  (void)fd;
733  std::memcpy(&address, addr, addrlen);
734  return 0;
735  });
736  // Mock 'close'.
737  fakeit::When(Method(mock_sys, close)).Return(0);
738  SECTION("Without explicit IP address.")
739  {
740  UnixUDPSocket socket(14050, {}, 0, mock_unique(mock_sys));
741  REQUIRE(
742  str(socket) ==
743  "udp {\n"
744  " port 14050;\n"
745  "}");
746  }
747  SECTION("With explicit IP address.")
748  {
749  UnixUDPSocket socket(
750  14050, IPAddress("127.0.0.1"), 0, mock_unique(mock_sys));
751  REQUIRE(
752  str(socket) ==
753  "udp {\n"
754  " port 14050;\n"
755  " address 127.0.0.1;\n"
756  "}");
757  }
758  SECTION("Without explicit IP address (and maximum bitrate).")
759  {
760  UnixUDPSocket socket(14050, {}, 8192, mock_unique(mock_sys));
761  REQUIRE(
762  str(socket) ==
763  "udp {\n"
764  " port 14050;\n"
765  " max_bitrate 8192;\n"
766  "}");
767  }
768  SECTION("With explicit IP address (and maximum bitrate).")
769  {
770  UnixUDPSocket socket(
771  14050, IPAddress("127.0.0.1"), 8192, mock_unique(mock_sys));
772  REQUIRE(
773  str(socket) ==
774  "udp {\n"
775  " port 14050;\n"
776  " address 127.0.0.1;\n"
777  " max_bitrate 8192;\n"
778  "}");
779  }
780 }
TEST_CASE("UnixUDPSocket's create and bind a UDP socket on construction and " "closes the socket on destruction.", "[UnixUDPSocket]")
std::string str(const T &object)
Definition: utility.hpp:128
virtual void send(const std::vector< uint8_t > &data, const IPAddress &address) final
std::unique_ptr< T > mock_unique(fakeit::Mock< T > &mock)
Definition: common.hpp:46