| 3599 | #endif |
| 3600 | |
| 3601 | inline socket_t create_client_socket( |
| 3602 | const std::string &host, const std::string &ip, int port, |
| 3603 | int address_family, bool tcp_nodelay, bool ipv6_v6only, |
| 3604 | SocketOptions socket_options, time_t connection_timeout_sec, |
| 3605 | time_t connection_timeout_usec, time_t read_timeout_sec, |
| 3606 | time_t read_timeout_usec, time_t write_timeout_sec, |
| 3607 | time_t write_timeout_usec, const std::string &intf, Error &error) { |
| 3608 | auto sock = create_socket( |
| 3609 | host, ip, port, address_family, 0, tcp_nodelay, ipv6_v6only, |
| 3610 | std::move(socket_options), |
| 3611 | [&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool { |
| 3612 | if (!intf.empty()) { |
| 3613 | #ifdef USE_IF2IP |
| 3614 | auto ip_from_if = if2ip(address_family, intf); |
| 3615 | if (ip_from_if.empty()) { ip_from_if = intf; } |
| 3616 | if (!bind_ip_address(sock2, ip_from_if)) { |
| 3617 | error = Error::BindIPAddress; |
| 3618 | return false; |
| 3619 | } |
| 3620 | #endif |
| 3621 | } |
| 3622 | |
| 3623 | set_nonblocking(sock2, true); |
| 3624 | |
| 3625 | auto ret = |
| 3626 | ::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen)); |
| 3627 | |
| 3628 | if (ret < 0) { |
| 3629 | if (is_connection_error()) { |
| 3630 | error = Error::Connection; |
| 3631 | return false; |
| 3632 | } |
| 3633 | error = wait_until_socket_is_ready(sock2, connection_timeout_sec, |
| 3634 | connection_timeout_usec); |
| 3635 | if (error != Error::Success) { |
| 3636 | if (error == Error::ConnectionTimeout) { quit = true; } |
| 3637 | return false; |
| 3638 | } |
| 3639 | } |
| 3640 | |
| 3641 | set_nonblocking(sock2, false); |
| 3642 | |
| 3643 | { |
| 3644 | #ifdef _WIN32 |
| 3645 | auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 + |
| 3646 | read_timeout_usec / 1000); |
| 3647 | setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, |
| 3648 | reinterpret_cast<const char *>(&timeout), sizeof(timeout)); |
| 3649 | #else |
| 3650 | timeval tv; |
| 3651 | tv.tv_sec = static_cast<long>(read_timeout_sec); |
| 3652 | tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec); |
| 3653 | setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, |
| 3654 | reinterpret_cast<const void *>(&tv), sizeof(tv)); |
| 3655 | #endif |
| 3656 | } |
| 3657 | { |
| 3658 |
no test coverage detected