| 2943 | } |
| 2944 | |
| 2945 | cbm_daemon_ipc_connection_t *cbm_daemon_ipc_connect(const cbm_daemon_ipc_endpoint_t *endpoint, |
| 2946 | uint32_t timeout_ms) { |
| 2947 | if (!endpoint_runtime_still_valid(endpoint)) { |
| 2948 | return NULL; |
| 2949 | } |
| 2950 | uint64_t deadline_ms = ipc_deadline_after(timeout_ms); |
| 2951 | for (;;) { |
| 2952 | struct stat status; |
| 2953 | if (fstatat(endpoint->dir_fd, endpoint->socket_name, &status, AT_SYMLINK_NOFOLLOW) != 0) { |
| 2954 | int path_error = errno; |
| 2955 | if (path_error == ENOENT && ipc_retry_pause(deadline_ms)) { |
| 2956 | continue; |
| 2957 | } |
| 2958 | return NULL; |
| 2959 | } |
| 2960 | if (!posix_socket_status_secure_transport(&status)) { |
| 2961 | return NULL; |
| 2962 | } |
| 2963 | |
| 2964 | int fd = local_socket_new(); |
| 2965 | if (fd < 0) { |
| 2966 | return NULL; |
| 2967 | } |
| 2968 | struct sockaddr_un address; |
| 2969 | socklen_t address_length; |
| 2970 | if (!unix_address_set(&address, endpoint->address, &address_length)) { |
| 2971 | (void)close(fd); |
| 2972 | return NULL; |
| 2973 | } |
| 2974 | |
| 2975 | int result = local_socket_connect(fd, &address, address_length); |
| 2976 | int connect_error = result == 0 ? 0 : errno; |
| 2977 | if (result != 0 && connect_error != EINPROGRESS && connect_error != EAGAIN && |
| 2978 | connect_error != EWOULDBLOCK) { |
| 2979 | (void)close(fd); |
| 2980 | if ((connect_error == ENOENT || connect_error == ECONNREFUSED) && |
| 2981 | ipc_retry_pause(deadline_ms)) { |
| 2982 | continue; |
| 2983 | } |
| 2984 | return NULL; |
| 2985 | } |
| 2986 | if (result != 0) { |
| 2987 | int ready = poll_until(fd, POLLOUT, deadline_ms); |
| 2988 | int socket_error = 0; |
| 2989 | socklen_t error_length = sizeof(socket_error); |
| 2990 | if (ready != 1 || |
| 2991 | getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &error_length) != 0) { |
| 2992 | (void)close(fd); |
| 2993 | return NULL; |
| 2994 | } |
| 2995 | if (socket_error != 0) { |
| 2996 | (void)close(fd); |
| 2997 | if ((socket_error == ENOENT || socket_error == ECONNREFUSED) && |
| 2998 | ipc_retry_pause(deadline_ms)) { |
| 2999 | continue; |
| 3000 | } |
| 3001 | return NULL; |
| 3002 | } |