| 3157 | #endif |
| 3158 | |
| 3159 | inline socket_t create_client_socket( |
| 3160 | const std::string &host, const std::string &ip, int port, |
| 3161 | int address_family, bool tcp_nodelay, SocketOptions socket_options, |
| 3162 | time_t connection_timeout_sec, time_t connection_timeout_usec, |
| 3163 | time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, |
| 3164 | time_t write_timeout_usec, const std::string &intf, Error &error) { |
| 3165 | auto sock = create_socket( |
| 3166 | host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options), |
| 3167 | [&](socket_t sock2, struct addrinfo &ai) -> bool { |
| 3168 | if (!intf.empty()) { |
| 3169 | #ifdef USE_IF2IP |
| 3170 | auto ip_from_if = if2ip(address_family, intf); |
| 3171 | if (ip_from_if.empty()) { ip_from_if = intf; } |
| 3172 | if (!bind_ip_address(sock2, ip_from_if.c_str())) { |
| 3173 | error = Error::BindIPAddress; |
| 3174 | return false; |
| 3175 | } |
| 3176 | #endif |
| 3177 | } |
| 3178 | |
| 3179 | set_nonblocking(sock2, true); |
| 3180 | |
| 3181 | auto ret = |
| 3182 | ::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen)); |
| 3183 | |
| 3184 | if (ret < 0) { |
| 3185 | if (is_connection_error()) { |
| 3186 | error = Error::Connection; |
| 3187 | return false; |
| 3188 | } |
| 3189 | error = wait_until_socket_is_ready(sock2, connection_timeout_sec, |
| 3190 | connection_timeout_usec); |
| 3191 | if (error != Error::Success) { return false; } |
| 3192 | } |
| 3193 | |
| 3194 | set_nonblocking(sock2, false); |
| 3195 | |
| 3196 | { |
| 3197 | #ifdef _WIN32 |
| 3198 | auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 + |
| 3199 | read_timeout_usec / 1000); |
| 3200 | setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, |
| 3201 | reinterpret_cast<const char *>(&timeout), sizeof(timeout)); |
| 3202 | #else |
| 3203 | timeval tv; |
| 3204 | tv.tv_sec = static_cast<long>(read_timeout_sec); |
| 3205 | tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec); |
| 3206 | setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, |
| 3207 | reinterpret_cast<const void *>(&tv), sizeof(tv)); |
| 3208 | #endif |
| 3209 | } |
| 3210 | { |
| 3211 | |
| 3212 | #ifdef _WIN32 |
| 3213 | auto timeout = static_cast<uint32_t>(write_timeout_sec * 1000 + |
| 3214 | write_timeout_usec / 1000); |
| 3215 | setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, |
| 3216 | reinterpret_cast<const char *>(&timeout), sizeof(timeout)); |
no test coverage detected