MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / PCPSendRecv

Function PCPSendRecv

src/common/pcp.cpp:224–278  ·  view source on GitHub ↗

PCP or NAT-PMP send-receive loop.

Source from the content-addressed store, hash-verified

222
223//! PCP or NAT-PMP send-receive loop.
224std::optional<std::vector<uint8_t>> PCPSendRecv(Sock &sock, const std::string &protocol, std::span<const uint8_t> request, int num_tries,
225 std::chrono::milliseconds timeout_per_try,
226 std::function<bool(std::span<const uint8_t>)> check_packet,
227 CThreadInterrupt& interrupt)
228{
229 using namespace std::chrono;
230 // UDP is a potentially lossy protocol, so we try to send again a few times.
231 uint8_t response[PCP_MAX_SIZE];
232 bool got_response = false;
233 int recvsz = 0;
234 for (int ntry = 0; !got_response && ntry < num_tries; ++ntry) {
235 if (ntry > 0) {
236 LogDebug(BCLog::NET, "%s: Retrying (%d)\n", protocol, ntry);
237 }
238 // Dispatch packet to gateway.
239 if (sock.Send(request.data(), request.size(), 0) != static_cast<ssize_t>(request.size())) {
240 LogDebug(BCLog::NET, "%s: Could not send request: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
241 return std::nullopt; // Network-level error, probably no use retrying.
242 }
243
244 // Wait for response(s) until we get a valid response, a network error, or time out.
245 auto cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now());
246 auto deadline = cur_time + timeout_per_try;
247 while ((cur_time = time_point_cast<milliseconds>(MockableSteadyClock::now())) < deadline) {
248 if (interrupt) return std::nullopt;
249 Sock::Event occurred = 0;
250 if (!sock.Wait(deadline - cur_time, Sock::RecvEvent, &occurred)) {
251 LogWarning("%s: Could not wait on socket: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
252 return std::nullopt; // Network-level error, probably no use retrying.
253 }
254 if (!occurred) {
255 LogDebug(BCLog::NET, "%s: Timeout\n", protocol);
256 break; // Retry.
257 }
258
259 // Receive response.
260 recvsz = sock.Recv(response, sizeof(response), MSG_DONTWAIT);
261 if (recvsz < 0) {
262 LogDebug(BCLog::NET, "%s: Could not receive response: %s\n", protocol, NetworkErrorString(WSAGetLastError()));
263 return std::nullopt; // Network-level error, probably no use retrying.
264 }
265 LogDebug(BCLog::NET, "%s: Received response of %d bytes: %s\n", protocol, recvsz, HexStr(std::span(response, recvsz)));
266
267 if (check_packet(std::span<uint8_t>(response, recvsz))) {
268 got_response = true; // Got expected response, break from receive loop as well as from retry loop.
269 break;
270 }
271 }
272 }
273 if (!got_response) {
274 LogDebug(BCLog::NET, "%s: Giving up after %d tries\n", protocol, num_tries);
275 return std::nullopt;
276 }
277 return std::vector<uint8_t>(response, response + recvsz);
278}
279
280}
281

Callers 2

NATPMPRequestPortMapFunction · 0.85
PCPRequestPortMapFunction · 0.85

Calls 7

NetworkErrorStringFunction · 0.85
HexStrFunction · 0.50
SendMethod · 0.45
dataMethod · 0.45
sizeMethod · 0.45
WaitMethod · 0.45
RecvMethod · 0.45

Tested by

no test coverage detected