| 3363 | |
| 3364 | template <typename BindOrConnect> |
| 3365 | socket_t create_socket(const std::string &host, const std::string &ip, int port, |
| 3366 | int address_family, int socket_flags, bool tcp_nodelay, |
| 3367 | bool ipv6_v6only, SocketOptions socket_options, |
| 3368 | BindOrConnect bind_or_connect) { |
| 3369 | // Get address info |
| 3370 | const char *node = nullptr; |
| 3371 | struct addrinfo hints; |
| 3372 | struct addrinfo *result; |
| 3373 | |
| 3374 | memset(&hints, 0, sizeof(struct addrinfo)); |
| 3375 | hints.ai_socktype = SOCK_STREAM; |
| 3376 | hints.ai_protocol = IPPROTO_IP; |
| 3377 | |
| 3378 | if (!ip.empty()) { |
| 3379 | node = ip.c_str(); |
| 3380 | // Ask getaddrinfo to convert IP in c-string to address |
| 3381 | hints.ai_family = AF_UNSPEC; |
| 3382 | hints.ai_flags = AI_NUMERICHOST; |
| 3383 | } else { |
| 3384 | if (!host.empty()) { node = host.c_str(); } |
| 3385 | hints.ai_family = address_family; |
| 3386 | hints.ai_flags = socket_flags; |
| 3387 | } |
| 3388 | |
| 3389 | #ifndef _WIN32 |
| 3390 | if (hints.ai_family == AF_UNIX) { |
| 3391 | const auto addrlen = host.length(); |
| 3392 | if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; } |
| 3393 | |
| 3394 | #ifdef SOCK_CLOEXEC |
| 3395 | auto sock = socket(hints.ai_family, hints.ai_socktype | SOCK_CLOEXEC, |
| 3396 | hints.ai_protocol); |
| 3397 | #else |
| 3398 | auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); |
| 3399 | #endif |
| 3400 | |
| 3401 | if (sock != INVALID_SOCKET) { |
| 3402 | sockaddr_un addr{}; |
| 3403 | addr.sun_family = AF_UNIX; |
| 3404 | |
| 3405 | auto unescaped_host = unescape_abstract_namespace_unix_domain(host); |
| 3406 | std::copy(unescaped_host.begin(), unescaped_host.end(), addr.sun_path); |
| 3407 | |
| 3408 | hints.ai_addr = reinterpret_cast<sockaddr *>(&addr); |
| 3409 | hints.ai_addrlen = static_cast<socklen_t>( |
| 3410 | sizeof(addr) - sizeof(addr.sun_path) + addrlen); |
| 3411 | |
| 3412 | #ifndef SOCK_CLOEXEC |
| 3413 | fcntl(sock, F_SETFD, FD_CLOEXEC); |
| 3414 | #endif |
| 3415 | |
| 3416 | if (socket_options) { socket_options(sock); } |
| 3417 | |
| 3418 | bool dummy; |
| 3419 | if (!bind_or_connect(sock, hints, dummy)) { |
| 3420 | close_socket(sock); |
| 3421 | sock = INVALID_SOCKET; |
| 3422 | } |
no test coverage detected