| 539 | } |
| 540 | |
| 541 | bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nTimeout, bool manual_connection) |
| 542 | { |
| 543 | // Create a sockaddr from the specified service. |
| 544 | struct sockaddr_storage sockaddr; |
| 545 | socklen_t len = sizeof(sockaddr); |
| 546 | if (sock.Get() == INVALID_SOCKET) { |
| 547 | LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString()); |
| 548 | return false; |
| 549 | } |
| 550 | if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { |
| 551 | LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString()); |
| 552 | return false; |
| 553 | } |
| 554 | |
| 555 | // Connect to the addrConnect service on the hSocket socket. |
| 556 | if (sock.Connect(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) { |
| 557 | int nErr = WSAGetLastError(); |
| 558 | // WSAEINVAL is here because some legacy version of winsock uses it |
| 559 | if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) |
| 560 | { |
| 561 | // Connection didn't actually fail, but is being established |
| 562 | // asynchronously. Thus, use async I/O api (select/poll) |
| 563 | // synchronously to check for successful connection with a timeout. |
| 564 | const Sock::Event requested = Sock::RECV | Sock::SEND; |
| 565 | Sock::Event occurred; |
| 566 | if (!sock.Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) { |
| 567 | LogPrintf("wait for connect to %s failed: %s\n", |
| 568 | addrConnect.ToString(), |
| 569 | NetworkErrorString(WSAGetLastError())); |
| 570 | return false; |
| 571 | } else if (occurred == 0) { |
| 572 | LogPrint(BCLog::NET, "connection attempt to %s timed out\n", addrConnect.ToString()); |
| 573 | return false; |
| 574 | } |
| 575 | |
| 576 | // Even if the wait was successful, the connect might not |
| 577 | // have been successful. The reason for this failure is hidden away |
| 578 | // in the SO_ERROR for the socket in modern systems. We read it into |
| 579 | // sockerr here. |
| 580 | int sockerr; |
| 581 | socklen_t sockerr_len = sizeof(sockerr); |
| 582 | if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&sockerr, &sockerr_len) == |
| 583 | SOCKET_ERROR) { |
| 584 | LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); |
| 585 | return false; |
| 586 | } |
| 587 | if (sockerr != 0) { |
| 588 | LogConnectFailure(manual_connection, |
| 589 | "connect() to %s failed after wait: %s", |
| 590 | addrConnect.ToString(), |
| 591 | NetworkErrorString(sockerr)); |
| 592 | return false; |
| 593 | } |
| 594 | } |
| 595 | #ifdef WIN32 |
| 596 | else if (WSAGetLastError() != WSAEISCONN) |
| 597 | #else |
| 598 | else |
no test coverage detected