LCOV - code coverage report
Current view: top level - src/test - pcp_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 89.4 % 255 228
Test Date: 2025-02-22 05:08:25 Functions: 82.4 % 51 42
Branches: 50.0 % 1202 601

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2024 The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <common/pcp.h>
       6                 :             : #include <netbase.h>
       7                 :             : #include <test/util/logging.h>
       8                 :             : #include <test/util/setup_common.h>
       9                 :             : #include <util/time.h>
      10                 :             : 
      11                 :             : #include <boost/test/unit_test.hpp>
      12                 :             : 
      13                 :             : #include <algorithm>
      14                 :             : #include <deque>
      15                 :             : 
      16                 :             : using namespace std::literals;
      17                 :             : 
      18                 :             : /// UDP test server operation.
      19   [ +  -  +  - ]:         104 : struct TestOp {
      20                 :             :     std::chrono::milliseconds delay;
      21                 :             :     enum Op {
      22                 :             :         SEND, // Expect send (with optional data)
      23                 :             :         RECV, // Expect receive (with data)
      24                 :             :         NOP,  // Just delay
      25                 :             :     } op;
      26                 :             :     std::vector<uint8_t> data;
      27                 :             : 
      28                 :             :     //! Injected error.
      29                 :             :     //! Set this field to a non-zero value to return the errno code from send or receive operation.
      30                 :             :     int error;
      31                 :             : 
      32   [ +  -  +  - ]:           2 :     TestOp(std::chrono::milliseconds delay_in, Op op_in, const std::vector<uint8_t> &data_in, int error_in):
      33   [ +  -  +  -  :          24 :         delay(delay_in), op(op_in), data(data_in), error(error_in) {}
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
      34                 :             : };
      35                 :             : 
      36                 :             : /// Save the value of CreateSock and restore when the test ends.
      37                 :             : class PCPTestingSetup : public BasicTestingSetup
      38                 :             : {
      39                 :             : public:
      40                 :          10 :     explicit PCPTestingSetup(const ChainType chainType = ChainType::MAIN,
      41                 :             :                              TestOpts opts = {})
      42                 :          10 :         : BasicTestingSetup{chainType, opts},
      43   [ +  -  +  -  :          20 :           m_create_sock_orig{CreateSock}
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      44                 :             :     {
      45   [ +  -  +  -  :          20 :         const std::optional<CService> local_ipv4{Lookup("192.168.0.6", 1, false)};
                   +  - ]
      46   [ +  -  +  -  :          20 :         const std::optional<CService> local_ipv6{Lookup("2a10:1234:5678:9abc:def0:1234:5678:9abc", 1, false)};
                   +  - ]
      47   [ +  -  +  -  :          20 :         const std::optional<CService> gateway_ipv4{Lookup("192.168.0.1", 1, false)};
                   +  - ]
      48   [ +  -  +  -  :          20 :         const std::optional<CService> gateway_ipv6{Lookup("2a10:1234:5678:9abc:def0:0000:0000:0000", 1, false)};
                   +  - ]
      49   [ +  -  +  -  :          20 :         BOOST_REQUIRE(local_ipv4 && local_ipv6 && gateway_ipv4 && gateway_ipv6);
          +  -  +  -  -  
                +  +  - ]
      50                 :          10 :         default_local_ipv4 = *local_ipv4;
      51                 :          10 :         default_local_ipv6 = *local_ipv6;
      52                 :          10 :         default_gateway_ipv4 = *gateway_ipv4;
      53                 :          10 :         default_gateway_ipv6 = *gateway_ipv6;
      54                 :             : 
      55                 :          10 :         struct in_addr inaddr_any;
      56         [ +  - ]:          10 :         inaddr_any.s_addr = htonl(INADDR_ANY);
      57         [ +  - ]:          10 :         bind_any_ipv4 = CNetAddr(inaddr_any);
      58                 :          10 :     }
      59                 :             : 
      60                 :          10 :     ~PCPTestingSetup()
      61                 :          10 :     {
      62                 :          10 :         CreateSock = m_create_sock_orig;
      63                 :          10 :         MockableSteadyClock::ClearMockTime();
      64                 :          10 :     }
      65                 :             : 
      66                 :             :     // Default testing nonce.
      67                 :             :     static constexpr PCPMappingNonce TEST_NONCE{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc};
      68                 :             :     // Default network addresses.
      69                 :             :     CNetAddr default_local_ipv4;
      70                 :             :     CNetAddr default_local_ipv6;
      71                 :             :     CNetAddr default_gateway_ipv4;
      72                 :             :     CNetAddr default_gateway_ipv6;
      73                 :             :     // IPv4 bind
      74                 :             :     CNetAddr bind_any_ipv4;
      75                 :             : private:
      76                 :             :     const decltype(CreateSock) m_create_sock_orig;
      77                 :             : };
      78                 :             : 
      79                 :             : /** Simple scripted UDP server emulation for testing.
      80                 :             :  */
      81                 :             : class PCPTestSock final : public Sock
      82                 :             : {
      83                 :             : public:
      84                 :             :     // Note: we awkwardly mark all methods as const, and properties as mutable,
      85                 :             :     // because Sock expects all networking calls to be const.
      86                 :          11 :     explicit PCPTestSock(const CNetAddr &local_ip, const CNetAddr &gateway_ip, const std::vector<TestOp> &script)
      87                 :          11 :         : Sock{INVALID_SOCKET},
      88                 :          11 :           m_script(script),
      89                 :          11 :           m_local_ip(local_ip),
      90   [ +  -  +  - ]:          22 :           m_gateway_ip(gateway_ip)
      91                 :             :     {
      92                 :          11 :         ElapseTime(std::chrono::seconds(0)); // start mocking steady time
      93         [ +  - ]:          11 :         PrepareOp();
      94                 :          11 :     }
      95                 :             : 
      96                 :           0 :     PCPTestSock& operator=(Sock&& other) override
      97                 :             :     {
      98                 :           0 :         assert(false && "Move of Sock into PCPTestSock not allowed.");
      99                 :             :         return *this;
     100                 :             :     }
     101                 :             : 
     102                 :          16 :     ssize_t Send(const void* data, size_t len, int) const override {
     103         [ +  - ]:          16 :         if (!m_connected) return -1;
     104         [ +  + ]:          16 :         Span in_pkt = Span(static_cast<const uint8_t*>(data), len);
     105         [ -  + ]:          13 :         if (AtEndOfScript() || CurOp().op != TestOp::SEND) {
     106                 :             :             // Ignore sends after end of script, or sends when we expect a receive.
     107                 :           3 :             FailScript();
     108                 :           3 :             return len;
     109                 :             :         }
     110         [ +  - ]:          13 :         if (CurOp().error) return -1; // Inject failure
     111   [ +  +  -  + ]:          13 :         if (CurOp().data.empty() || std::ranges::equal(CurOp().data, in_pkt)) {
     112                 :          13 :             AdvanceOp();
     113                 :             :         } else {
     114                 :             :             // Wrong send, fail script
     115                 :           0 :             FailScript();
     116                 :             :         }
     117                 :          13 :         return len;
     118                 :             :     }
     119                 :             : 
     120                 :          12 :     ssize_t Recv(void* buf, size_t len, int flags) const override
     121                 :             :     {
     122   [ +  -  +  -  :          12 :         if (!m_connected || AtEndOfScript() || CurOp().op != TestOp::RECV || m_time_left != 0s) {
             +  -  -  + ]
     123                 :           0 :             return -1;
     124                 :             :         }
     125         [ +  + ]:          12 :         if (CurOp().error) return -1; // Inject failure
     126                 :          11 :         const auto &recv_pkt = CurOp().data;
     127         [ -  + ]:          11 :         const size_t consume_bytes{std::min(len, recv_pkt.size())};
     128         [ +  - ]:          11 :         std::memcpy(buf, recv_pkt.data(), consume_bytes);
     129         [ +  - ]:          11 :         if ((flags & MSG_PEEK) == 0) {
     130                 :          11 :             AdvanceOp();
     131                 :             :         }
     132                 :          11 :         return consume_bytes;
     133                 :             :     }
     134                 :             : 
     135                 :          11 :     int Connect(const sockaddr* sa, socklen_t sa_len) const override {
     136                 :          11 :         CService service;
     137   [ +  -  +  -  :          22 :         if (service.SetSockAddr(sa, sa_len) && service == CService(m_gateway_ip, 5351)) {
          +  -  +  -  +  
                -  +  - ]
     138   [ +  -  +  + ]:          11 :             if (m_bound.IsBindAny()) { // If bind-any, bind to local ip.
     139         [ +  - ]:           9 :                 m_bound = CService(m_local_ip, 0);
     140                 :             :             }
     141   [ +  -  +  - ]:          11 :             if (m_bound.GetPort() == 0) { // If no port assigned, assign port 1.
     142         [ +  - ]:          11 :                 m_bound = CService(m_bound, 1);
     143                 :             :             }
     144                 :          11 :             m_connected = true;
     145                 :          11 :             return 0;
     146                 :             :         }
     147                 :             :         return -1;
     148                 :          11 :     }
     149                 :             : 
     150                 :           8 :     int Bind(const sockaddr* sa, socklen_t sa_len) const override {
     151                 :           8 :         CService service;
     152   [ +  -  +  - ]:           8 :         if (service.SetSockAddr(sa, sa_len)) {
     153                 :             :             // Can only bind to one of our local ips
     154   [ +  -  +  +  :           8 :             if (!service.IsBindAny() && service != m_local_ip) {
             +  -  +  - ]
     155                 :             :                 return -1;
     156                 :             :             }
     157                 :           8 :             m_bound = service;
     158                 :           8 :             return 0;
     159                 :             :         }
     160                 :             :         return -1;
     161                 :           8 :     }
     162                 :             : 
     163                 :           0 :     int Listen(int) const override { return -1; }
     164                 :             : 
     165                 :           0 :     std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override
     166                 :             :     {
     167                 :           0 :         return nullptr;
     168                 :             :     };
     169                 :             : 
     170                 :           0 :     int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override
     171                 :             :     {
     172                 :           0 :         return -1;
     173                 :             :     }
     174                 :             : 
     175                 :           0 :     int SetSockOpt(int, int, const void*, socklen_t) const override { return 0; }
     176                 :             : 
     177                 :          11 :     int GetSockName(sockaddr* name, socklen_t* name_len) const override
     178                 :             :     {
     179                 :             :         // Return the address we've been bound to.
     180         [ -  + ]:          11 :         return m_bound.GetSockAddr(name, name_len) ? 0 : -1;
     181                 :             :     }
     182                 :             : 
     183                 :           0 :     bool SetNonBlocking() const override { return true; }
     184                 :             : 
     185                 :           0 :     bool IsSelectable() const override { return true; }
     186                 :             : 
     187                 :          16 :     bool Wait(std::chrono::milliseconds timeout,
     188                 :             :               Event requested,
     189                 :             :               Event* occurred = nullptr) const override
     190                 :             :     {
     191                 :             :         // Only handles receive events.
     192         [ +  - ]:          13 :         if (AtEndOfScript() || requested != Sock::RECV) {
     193                 :           3 :             ElapseTime(timeout);
     194                 :             :         } else {
     195                 :          13 :             std::chrono::milliseconds delay = std::min(m_time_left, timeout);
     196                 :          26 :             ElapseTime(delay);
     197                 :          13 :             m_time_left -= delay;
     198   [ +  +  +  -  :          13 :             if (CurOp().op == TestOp::RECV && m_time_left == 0s && occurred != nullptr) {
                   +  - ]
     199                 :          12 :                 *occurred = Sock::RECV;
     200                 :             :             }
     201         [ +  + ]:          13 :             if (CurOp().op == TestOp::NOP) {
     202                 :             :                 // This was a pure delay operation, move to the next op.
     203                 :           1 :                 AdvanceOp();
     204                 :             :             }
     205                 :             :         }
     206                 :          16 :         return true;
     207                 :             :     }
     208                 :             : 
     209                 :           0 :     bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override
     210                 :             :     {
     211                 :           0 :         return false;
     212                 :             :     }
     213                 :             : 
     214                 :           0 :     bool IsConnected(std::string&) const override
     215                 :             :     {
     216                 :           0 :         return true;
     217                 :             :     }
     218                 :             : 
     219                 :             : private:
     220                 :             :     const std::vector<TestOp> m_script;
     221                 :             :     mutable size_t m_script_ptr = 0;
     222                 :             :     mutable std::chrono::milliseconds m_time_left;
     223                 :             :     mutable std::chrono::milliseconds m_time{MockableSteadyClock::INITIAL_MOCK_TIME};
     224                 :             :     mutable bool m_connected{false};
     225                 :             :     mutable CService m_bound;
     226                 :             :     mutable CNetAddr m_local_ip;
     227                 :             :     mutable CNetAddr m_gateway_ip;
     228                 :             : 
     229                 :          27 :     void ElapseTime(std::chrono::milliseconds duration) const
     230                 :             :     {
     231         [ +  - ]:          27 :         m_time += duration;
     232         [ +  - ]:          27 :         MockableSteadyClock::SetMockTime(m_time);
     233                 :          14 :     }
     234                 :             : 
     235   [ +  +  +  -  :          44 :     bool AtEndOfScript() const { return m_script_ptr == m_script.size(); }
                   +  + ]
     236                 :         138 :     const TestOp &CurOp() const {
     237         [ +  - ]:         276 :         BOOST_REQUIRE(m_script_ptr < m_script.size());
     238                 :         138 :         return m_script[m_script_ptr];
     239                 :             :     }
     240                 :             : 
     241                 :          36 :     void PrepareOp() const {
     242         [ +  + ]:          36 :         if (AtEndOfScript()) return;
     243                 :          26 :         m_time_left = CurOp().delay;
     244                 :             :     }
     245                 :             : 
     246                 :          25 :     void AdvanceOp() const
     247                 :             :     {
     248                 :          25 :         m_script_ptr += 1;
     249                 :          25 :         PrepareOp();
     250                 :          25 :     }
     251                 :             : 
     252                 :           3 :     void FailScript() const { m_script_ptr = m_script.size(); }
     253                 :             : };
     254                 :             : 
     255                 :             : BOOST_FIXTURE_TEST_SUITE(pcp_tests, PCPTestingSetup)
     256                 :             : 
     257                 :             : // NAT-PMP IPv4 good-weather scenario.
     258   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(natpmp_ipv4)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     259                 :             : {
     260                 :           1 :     const std::vector<TestOp> script{
     261                 :             :         {
     262                 :             :             0ms, TestOp::SEND,
     263                 :             :             {
     264                 :             :                 0x00, 0x00, // version, opcode (request external IP)
     265                 :             :             }, 0
     266                 :             :         },
     267                 :             :         {
     268                 :             :             2ms, TestOp::RECV,
     269                 :             :             {
     270                 :             :                 0x00, 0x80, 0x00, 0x00, // version, opcode (external IP), result code (success)
     271                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     272                 :             :                 0x01, 0x02, 0x03, 0x04, // external IP address
     273                 :             :             }, 0
     274                 :             :         },
     275                 :             :         {
     276                 :             :             0ms, TestOp::SEND,
     277                 :             :             {
     278                 :             :                 0x00, 0x02, 0x00, 0x00, // version, opcode (request map TCP)
     279                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     280                 :             :                 0x00, 0x00, 0x03, 0xe8, // requested mapping lifetime in seconds
     281                 :             :             }, 0
     282                 :             :         },
     283                 :             :         {
     284                 :             :             2ms, TestOp::RECV,
     285                 :             :             {
     286                 :             :                 0x00, 0x82, 0x00, 0x00, // version, opcode (mapped TCP)
     287                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     288                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, mapped external port
     289                 :             :                 0x00, 0x00, 0x01, 0xf4, // mapping lifetime in seconds
     290                 :             :             }, 0
     291                 :             :         },
     292   [ +  +  -  - ]:           6 :     };
     293                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     294   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     295                 :           0 :         return std::unique_ptr<PCPTestSock>();
     296                 :           1 :     };
     297                 :             : 
     298         [ +  - ]:           1 :     auto res = NATPMPRequestPortMap(default_gateway_ipv4, 1234, 1000, 1, 200ms);
     299                 :             : 
     300         [ +  - ]:           1 :     MappingResult* mapping = std::get_if<MappingResult>(&res);
     301   [ +  -  +  -  :           2 :     BOOST_REQUIRE(mapping);
                   +  - ]
     302   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->version, 0);
     303   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->internal.ToStringAddrPort(), "192.168.0.6:1234");
                   +  - ]
     304   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->external.ToStringAddrPort(), "1.2.3.4:1234");
                   +  - ]
     305   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->lifetime, 500);
     306   [ +  -  +  -  :           6 : }
          +  -  +  -  +  
                -  -  - ]
     307                 :             : 
     308                 :             : // PCP IPv4 good-weather scenario.
     309   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv4)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     310                 :             : {
     311                 :           1 :     const std::vector<TestOp> script{
     312                 :             :         {
     313                 :             :             0ms, TestOp::SEND,
     314                 :             :             {
     315                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     316                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     317                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     318                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     319                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     320                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     321                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     322                 :             :             }, 0
     323                 :             :         },
     324                 :             :         {
     325                 :             :             250ms, TestOp::RECV, // 250ms delay before answer
     326                 :             :             {
     327                 :             :                 0x02, 0x81, 0x00, 0x00, // version, opcode, result success
     328                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     329                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     330                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     331                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     332                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     333                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, // assigned external IP
     334                 :             :             }, 0
     335                 :             :         },
     336   [ +  +  -  - ]:           4 :     };
     337                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     338   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     339                 :           0 :         return std::unique_ptr<PCPTestSock>();
     340                 :           1 :     };
     341                 :             : 
     342         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, 1, 1000ms);
     343                 :             : 
     344         [ +  - ]:           1 :     MappingResult* mapping = std::get_if<MappingResult>(&res);
     345   [ +  -  +  -  :           2 :     BOOST_REQUIRE(mapping);
                   +  - ]
     346   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->version, 2);
     347   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->internal.ToStringAddrPort(), "192.168.0.6:1234");
                   +  - ]
     348   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->external.ToStringAddrPort(), "1.2.3.4:1234");
                   +  - ]
     349   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->lifetime, 500);
     350   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     351                 :             : 
     352                 :             : // PCP IPv6 good-weather scenario.
     353   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv6)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     354                 :             : {
     355                 :           1 :     const std::vector<TestOp> script{
     356                 :             :         {
     357                 :             :             0ms, TestOp::SEND,
     358                 :             :             {
     359                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     360                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     361                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // internal IP
     362                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     363                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     364                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     365                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     366                 :             :             }, 0
     367                 :             :         },
     368                 :             :         {
     369                 :             :             500ms, TestOp::RECV, // 500ms delay before answer
     370                 :             :             {
     371                 :             :                 0x02, 0x81, 0x00, 0x00, // version, opcode, result success
     372                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     373                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     374                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     375                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     376                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     377                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     378                 :             :             }, 0
     379                 :             :         },
     380   [ +  +  -  - ]:           4 :     };
     381                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     382   [ +  -  +  - ]:           1 :         if (domain == AF_INET6 && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv6, default_gateway_ipv6, script);
     383                 :           0 :         return std::unique_ptr<PCPTestSock>();
     384                 :           1 :     };
     385                 :             : 
     386         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv6, default_local_ipv6, 1234, 1000, 1, 1000ms);
     387                 :             : 
     388         [ +  - ]:           1 :     MappingResult* mapping = std::get_if<MappingResult>(&res);
     389   [ +  -  +  -  :           2 :     BOOST_REQUIRE(mapping);
                   +  - ]
     390   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->version, 2);
     391   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->internal.ToStringAddrPort(), "[2a10:1234:5678:9abc:def0:1234:5678:9abc]:1234");
                   +  - ]
     392   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mapping->external.ToStringAddrPort(), "[2a10:1234:5678:9abc:def0:1234:5678:9abc]:1234");
                   +  - ]
     393   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(mapping->lifetime, 500);
     394   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     395                 :             : 
     396                 :             : // PCP timeout.
     397   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_timeout)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     398                 :             : {
     399                 :           1 :     const std::vector<TestOp> script{};
     400                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     401   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     402                 :           0 :         return std::unique_ptr<PCPTestSock>();
     403                 :           1 :     };
     404                 :             : 
     405   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Retrying (1)");
     406   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Retrying (2)");
     407   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Timeout");
     408                 :             : 
     409         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, 3, 2000ms);
     410                 :             : 
     411         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     412   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     413   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::NETWORK_ERROR);
     414                 :           1 : }
     415                 :             : 
     416                 :             : // PCP failure receiving (router sends ICMP port closed).
     417   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_connrefused)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     418                 :             : {
     419                 :           1 :     const std::vector<TestOp> script{
     420                 :             :         {
     421                 :             :             0ms, TestOp::SEND,
     422                 :             :             { // May send anything.
     423                 :             :             }, 0
     424                 :             :         },
     425                 :             :         {
     426                 :             :             0ms, TestOp::RECV,
     427                 :             :             {
     428                 :             :             }, ECONNREFUSED
     429                 :             :         },
     430   [ +  +  -  - ]:           4 :     };
     431                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     432   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     433                 :           0 :         return std::unique_ptr<PCPTestSock>();
     434                 :           1 :     };
     435                 :             : 
     436   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Could not receive response");
     437                 :             : 
     438         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, 3, 2000ms);
     439                 :             : 
     440         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     441   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     442   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::NETWORK_ERROR);
     443   [ +  -  +  -  :           2 : }
             +  -  -  - ]
     444                 :             : 
     445                 :             : // PCP IPv6 success after one timeout.
     446   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv6_timeout_success)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     447                 :             : {
     448                 :           1 :     const std::vector<TestOp> script{
     449                 :             :         {
     450                 :             :             0ms, TestOp::SEND,
     451                 :             :             {
     452                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     453                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     454                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // internal IP
     455                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     456                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     457                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     458                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     459                 :             :             }, 0
     460                 :             :         },
     461                 :             :         {
     462                 :             :             2001ms, TestOp::NOP, // Takes longer to respond than timeout of 2000ms
     463                 :             :             {}, 0
     464                 :             :         },
     465                 :             :         {
     466                 :             :             0ms, TestOp::SEND, // Repeated send (try 2)
     467                 :             :             {
     468                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     469                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     470                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // internal IP
     471                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     472                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     473                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     474                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     475                 :             :             }, 0
     476                 :             :         },
     477                 :             :         {
     478                 :             :             200ms, TestOp::RECV, // This time we're in time
     479                 :             :             {
     480                 :             :                 0x02, 0x81, 0x00, 0x00, // version, opcode, result success
     481                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     482                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     483                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     484                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     485                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     486                 :             :                 0x2a, 0x10, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, // suggested external IP
     487                 :             :             }, 0
     488                 :             :         },
     489   [ +  +  -  - ]:           6 :     };
     490                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     491   [ +  -  +  - ]:           1 :         if (domain == AF_INET6 && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv6, default_gateway_ipv6, script);
     492                 :           0 :         return std::unique_ptr<PCPTestSock>();
     493                 :           1 :     };
     494                 :             : 
     495   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Retrying (1)");
     496   [ +  -  +  - ]:           2 :     ASSERT_DEBUG_LOG("pcp: Timeout");
     497                 :             : 
     498         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv6, default_local_ipv6, 1234, 1000, 2, 2000ms);
     499                 :             : 
     500   [ +  -  +  -  :           3 :     BOOST_CHECK(std::get_if<MappingResult>(&res));
                   +  - ]
     501   [ +  -  +  -  :           5 : }
          +  -  +  -  +  
                -  -  - ]
     502                 :             : 
     503                 :             : // PCP IPv4 failure (no resources).
     504   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv4_fail_no_resources)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     505                 :             : {
     506                 :           1 :     const std::vector<TestOp> script{
     507                 :             :         {
     508                 :             :             0ms, TestOp::SEND,
     509                 :             :             {
     510                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     511                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     512                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     513                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     514                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     515                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     516                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     517                 :             :             }, 0
     518                 :             :         },
     519                 :             :         {
     520                 :             :             500ms, TestOp::RECV,
     521                 :             :             {
     522                 :             :                 0x02, 0x81, 0x00, 0x08, // version, opcode, result 0x08: no resources
     523                 :             :                 0x00, 0x00, 0x00, 0x00, // granted lifetime
     524                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     525                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     526                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     527                 :             :                 0x04, 0xd2, 0x00, 0x00, // internal port, assigned external port
     528                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // assigned external IP
     529                 :             :             }, 0
     530                 :             :         },
     531   [ +  +  -  - ]:           4 :     };
     532                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     533   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     534                 :           0 :         return std::unique_ptr<PCPTestSock>();
     535                 :           1 :     };
     536                 :             : 
     537         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, 3, 1000ms);
     538                 :             : 
     539         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     540   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     541   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::NO_RESOURCES);
     542   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     543                 :             : 
     544                 :             : // PCP IPv4 failure (test NATPMP downgrade scenario).
     545   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_ipv4_fail_unsupported_version)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     546                 :             : {
     547                 :           1 :     const std::vector<TestOp> script{
     548                 :             :         {
     549                 :             :             0ms, TestOp::SEND,
     550                 :             :             {
     551                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     552                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     553                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     554                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     555                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     556                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     557                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     558                 :             :             }, 0
     559                 :             :         },
     560                 :             :         {
     561                 :             :             500ms, TestOp::RECV,
     562                 :             :             {
     563                 :             :                 0x00, 0x81, 0x00, 0x01, // version, opcode, result 0x01: unsupported version
     564                 :             :                 0x00, 0x00, 0x00, 0x00,
     565                 :             :             }, 0
     566                 :             :         },
     567   [ +  +  -  - ]:           4 :     };
     568                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     569   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     570                 :           0 :         return std::unique_ptr<PCPTestSock>();
     571                 :           1 :     };
     572                 :             : 
     573         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, 3, 1000ms);
     574                 :             : 
     575         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     576   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     577   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::UNSUPP_VERSION);
     578   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     579                 :             : 
     580                 :             : // NAT-PMP IPv4 protocol error scenarii.
     581   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(natpmp_protocol_error)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     582                 :             : {
     583                 :             :     // First scenario: non-0 result code when requesting external IP.
     584                 :           1 :     std::vector<TestOp> script{
     585                 :             :         {
     586                 :             :             0ms, TestOp::SEND,
     587                 :             :             {
     588                 :             :                 0x00, 0x00, // version, opcode (request external IP)
     589                 :             :             }, 0
     590                 :             :         },
     591                 :             :         {
     592                 :             :             2ms, TestOp::RECV,
     593                 :             :             {
     594                 :             :                 0x00, 0x80, 0x00, 0x42, // version, opcode (external IP), result code (*NOT* success)
     595                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     596                 :             :                 0x01, 0x02, 0x03, 0x04, // external IP address
     597                 :             :             }, 0
     598                 :             :         },
     599   [ +  +  -  - ]:           4 :     };
     600                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     601   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     602                 :           0 :         return std::unique_ptr<PCPTestSock>();
     603                 :           1 :     };
     604                 :             : 
     605         [ +  - ]:           1 :     auto res = NATPMPRequestPortMap(default_gateway_ipv4, 1234, 1000, 1, 200ms);
     606                 :             : 
     607         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     608   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     609   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::PROTOCOL_ERROR);
     610                 :             : 
     611                 :             :     // First scenario: non-0 result code when requesting port mapping.
     612   [ +  +  -  - ]:           5 :     script = {
     613                 :             :         {
     614                 :             :             0ms, TestOp::SEND,
     615                 :             :             {
     616                 :             :                 0x00, 0x00, // version, opcode (request external IP)
     617                 :             :             }, 0
     618                 :             :         },
     619                 :             :         {
     620                 :             :             2ms, TestOp::RECV,
     621                 :             :             {
     622                 :             :                 0x00, 0x80, 0x00, 0x00, // version, opcode (external IP), result code (success)
     623                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     624                 :             :                 0x01, 0x02, 0x03, 0x04, // external IP address
     625                 :             :             }, 0
     626                 :             :         },
     627                 :             :         {
     628                 :             :             0ms, TestOp::SEND,
     629                 :             :             {
     630                 :             :                 0x00, 0x02, 0x00, 0x00, // version, opcode (request map TCP)
     631                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     632                 :             :                 0x00, 0x00, 0x03, 0xe8, // requested mapping lifetime in seconds
     633                 :             :             }, 0
     634                 :             :         },
     635                 :             :         {
     636                 :             :             2ms, TestOp::RECV,
     637                 :             :             {
     638                 :             :                 0x00, 0x82, 0x00, 0x43, // version, opcode (mapped TCP)
     639                 :             :                 0x66, 0xfd, 0xa1, 0xee, // seconds sinds start of epoch
     640                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, mapped external port
     641                 :             :                 0x00, 0x00, 0x01, 0xf4, // mapping lifetime in seconds
     642                 :             :             }, 0
     643                 :             :         },
     644                 :           5 :     };
     645                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     646   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     647                 :           0 :         return std::unique_ptr<PCPTestSock>();
     648                 :           1 :     };
     649                 :             : 
     650         [ +  - ]:           2 :     res = NATPMPRequestPortMap(default_gateway_ipv4, 1234, 1000, 1, 200ms);
     651                 :             : 
     652         [ +  - ]:           1 :     err = std::get_if<MappingError>(&res);
     653   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     654   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::PROTOCOL_ERROR);
     655   [ +  -  +  -  :           9 : }
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  -  -  
                      - ]
     656                 :             : 
     657                 :             : // PCP IPv4 protocol error scenario.
     658   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(pcp_protocol_error)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     659                 :             : {
     660                 :           1 :     const std::vector<TestOp> script{
     661                 :             :         {
     662                 :             :             0ms, TestOp::SEND,
     663                 :             :             {
     664                 :             :                 0x02, 0x01, 0x00, 0x00, // version, opcode
     665                 :             :                 0x00, 0x00, 0x03, 0xe8, // lifetime
     666                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x06, // internal IP
     667                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     668                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     669                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, suggested external port
     670                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // suggested external IP
     671                 :             :             }, 0
     672                 :             :         },
     673                 :             :         {
     674                 :             :             250ms, TestOp::RECV, // 250ms delay before answer
     675                 :             :             {
     676                 :             :                 0x02, 0x81, 0x00, 0x42, // version, opcode, result error
     677                 :             :                 0x00, 0x00, 0x01, 0xf4, // granted lifetime
     678                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
     679                 :             :                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // nonce
     680                 :             :                 0x06, 0x00, 0x00, 0x00, // protocol (TCP), reserved
     681                 :             :                 0x04, 0xd2, 0x04, 0xd2, // internal port, assigned external port
     682                 :             :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, // assigned external IP
     683                 :             :             }, 0
     684                 :             :         },
     685   [ +  +  -  - ]:           4 :     };
     686                 :           2 :     CreateSock = [this, &script](int domain, int type, int protocol) {
     687   [ +  -  +  - ]:           1 :         if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) return std::make_unique<PCPTestSock>(default_local_ipv4, default_gateway_ipv4, script);
     688                 :           0 :         return std::unique_ptr<PCPTestSock>();
     689                 :           1 :     };
     690                 :             : 
     691         [ +  - ]:           1 :     auto res = PCPRequestPortMap(TEST_NONCE, default_gateway_ipv4, bind_any_ipv4, 1234, 1000, 1, 1000ms);
     692                 :             : 
     693         [ +  - ]:           1 :     MappingError* err = std::get_if<MappingError>(&res);
     694   [ +  -  +  -  :           2 :     BOOST_REQUIRE(err);
                   +  - ]
     695   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(*err, MappingError::PROTOCOL_ERROR);
     696   [ +  -  +  -  :           4 : }
             +  -  -  - ]
     697                 :             : 
     698                 :             : BOOST_AUTO_TEST_SUITE_END()
     699                 :             : 
        

Generated by: LCOV version 2.0-1