LCOV - code coverage report
Current view: top level - src/test - pcp_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 89.2 % 250 223
Test Date: 2026-06-27 07:07:37 Functions: 82.4 % 51 42
Branches: 49.8 % 1306 651

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

Generated by: LCOV version 2.0-1