Repository: bitcoin/bitcoin
File: src/common/pcp.cpp (C++)

Code before:
    } else {
        return false;
    }
}

//! Unwrap PCP-encoded address according to RFC6887.
CNetAddr PCPUnwrapAddress(std::span<const uint8_t> wrapped_addr)
{
    Assume(wrapped_addr.size() == ADDR_IPV6_SIZE);
    if (util::HasPrefix(wrapped_addr, IPV4_IN_IPV6_PREFIX)) {
        struct in_addr addr4;
        std::memcpy(&addr4, wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), ADDR_IPV4_SIZE);
        return CNetAddr(addr4);
    } else {
        struct in6_addr addr6;
        std::memcpy(&addr6, wrapped_addr.data(), ADDR_IPV6_SIZE);
        return CNetAddr(addr6);
    }
}

//! PCP or NAT-PMP send-receive loop.
std::optional<std::vector<uint8_t>> PCPSendRecv(Sock &sock, const std::string &protocol, std::span<const uint8_t> request, int num_tries,
        std::chrono::milliseconds timeout_per_try,
        std::function<bool(std::span<const uint8_t>)> check_packet)
{
    using namespace std::chrono;
    // UDP is a potentially lossy protocol, so we try to send again a few times.
    uint8_t response[PCP_MAX_SIZE];
    bool got_response = false;
    int recvsz = 0;
    for (int ntry = 0; !got_response && ntry < num_tries; ++ntry) {
        if (ntry > 0) {
            LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Retrying (%d)\n", protocol, ntry);
        }
        // Dispatch packet to gateway.
        if (sock.Send(request.data(), request.size(), 0) != static_cast<ssize_t>(request.size())) {
            LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Could not send request: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
            return std::nullopt; // Network-level error, probably no use retrying.
        }

        // Wait for response(s) until we get a valid response, a network error, or time out.
        auto cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now());
        auto deadline = cur_time + timeout_per_try;
        while ((cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now())) < deadline) {
            Sock::Event occurred = 0;
            if (!sock.Wait(deadline - cur_time, Sock::RECV, &occurred)) {
                LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "%s: Could not wait on socket: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
                return std::nullopt; // Network-level error, probably no use retrying.
            }
            if (!occurred) {
                LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Timeout\n", protocol);

Review comment (suggestion):
nit: Would prefer keeping the lambda as the last parameter and also avoiding to mix `&`-placement within the same argument list.
```suggestion
        CThreadInterrupt &interrupt,
        std::function<bool(std::span<const uint8_t>)> check_packet)
```

Code after:
        return true;
    } else {
        return false;
    }
}

//! Unwrap PCP-encoded address according to RFC6887.
CNetAddr PCPUnwrapAddress(std::span<const uint8_t> wrapped_addr)
{
    Assume(wrapped_addr.size() == ADDR_IPV6_SIZE);
    if (util::HasPrefix(wrapped_addr, IPV4_IN_IPV6_PREFIX)) {
        struct in_addr addr4;
        std::memcpy(&addr4, wrapped_addr.data() + IPV4_IN_IPV6_PREFIX.size(), ADDR_IPV4_SIZE);
        return CNetAddr(addr4);
    } else {
        struct in6_addr addr6;
        std::memcpy(&addr6, wrapped_addr.data(), ADDR_IPV6_SIZE);
        return CNetAddr(addr6);
    }
}

//! PCP or NAT-PMP send-receive loop.
std::optional<std::vector<uint8_t>> PCPSendRecv(Sock &sock, const std::string &protocol, std::span<const uint8_t> request, int num_tries,
        std::chrono::milliseconds timeout_per_try,
        std::function<bool(std::span<const uint8_t>)> check_packet,
        CThreadInterrupt& interrupt)
{
    using namespace std::chrono;
    // UDP is a potentially lossy protocol, so we try to send again a few times.
    uint8_t response[PCP_MAX_SIZE];
    bool got_response = false;
    int recvsz = 0;
    for (int ntry = 0; !got_response && ntry < num_tries; ++ntry) {
        if (ntry > 0) {
            LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "%s: Retrying (%d)\n", protocol, ntry);
        }
        // Dispatch packet to gateway.
        if (sock.Send(request.data(), request.size(), 0) != static_cast<ssize_t>(request.size())) {
            LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "%s: Could not send request: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
            return std::nullopt; // Network-level error, probably no use retrying.
        }

        // Wait for response(s) until we get a valid response, a network error, or time out.
        auto cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now());
        auto deadline = cur_time + timeout_per_try;
        while ((cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now())) < deadline) {
            if (interrupt) return std::nullopt;
            Sock::Event occurred = 0;
            if (!sock.Wait(deadline - cur_time, Sock::RECV, &occurred)) {
                LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "%s: Could not wait on socket: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
                return std::nullopt; // Network-level error, probably no use retrying.